Inspect and validate flag enums
To inspect and validate bitwise combinations of enum values in magic_enum, you must first enable flag support for your enum type and then use the specialized flag APIs.
Enabling Flag Support
By default, magic_enum treats enums as single-value selections. To enable bitwise operations and flag-specific string formatting, you must specialize the magic_enum::customize::enum_range struct for your enum type and set is_flags to true.
#include <magic_enum/magic_enum.hpp>
#include <magic_enum/magic_enum_flags.hpp>
#include <iostream>
enum class Color { RED = 1, GREEN = 2, BLUE = 4 };
// Enable flag support for Color
template <>
struct magic_enum::customize::enum_range<Color> {
static constexpr bool is_flags = true;
};
int main() {
using namespace magic_enum::bitwise_operators; // Enable operator| for Color
Color c = Color::RED | Color::BLUE;
// Now flag-specific APIs can be used
std::cout << magic_enum::enum_flags_name(c) << std::endl; // Output: RED|BLUE
return 0;
}
Formatting Flag Combinations
The magic_enum::enum_flags_name function produces a string representation of a bitwise combination of flags. It joins the names of all set flags using a separator (defaulting to |).
#include <magic_enum/magic_enum_flags.hpp>
#include <iostream>
#include <string>
enum class Permission { Read = 1, Write = 2, Execute = 4 };
template <>
struct magic_enum::customize::enum_range<Permission> {
static constexpr bool is_flags = true;
};
void print_permissions(Permission p) {
// Returns a string like "Read|Write"
std::string name = magic_enum::enum_flags_name(p);
if (name.empty()) {
std::cout << "No permissions or invalid value" << std::endl;
} else {
std::cout << "Permissions: " << name << std::endl;
}
}
int main() {
using namespace magic_enum::bitwise_operators;
print_permissions(Permission::Read | Permission::Write); // Output: Permissions: Read|Write
print_permissions(static_cast<Permission>(0)); // Output: No permissions or invalid value
return 0;
}
Customizing the Separator
You can provide a custom character as a second argument to enum_flags_name to change the delimiter.
#include <magic_enum/magic_enum_flags.hpp>
#include <iostream>
enum class Feature { A = 1, B = 2 };
template <>
struct magic_enum::customize::enum_range<Feature> {
static constexpr bool is_flags = true;
};
int main() {
using namespace magic_enum::bitwise_operators;
auto f = Feature::A | Feature::B;
// Use '+' as a separator instead of '|'
std::cout << magic_enum::enum_flags_name(f, '+') << std::endl; // Output: A+B
return 0;
}
Validating Flag Values
The magic_enum::enum_flags_contains function checks if a value (enum, integer, or string) represents a valid combination of the defined flags for that enum type.
Validating Enum and Integer Values
A value is considered valid if it is a bitwise combination of the reflected enum constants. A value of 0 is always considered invalid by enum_flags_contains.
#include <magic_enum/magic_enum_flags.hpp>
#include <iostream>
enum class Status { Active = 1, Pending = 2, Deleted = 4 };
template <>
struct magic_enum::customize::enum_range<Status> {
static constexpr bool is_flags = true;
};
int main() {
using namespace magic_enum::bitwise_operators;
// Valid combinations
bool valid1 = magic_enum::enum_flags_contains(Status::Active | Status::Pending); // true
bool valid2 = magic_enum::enum_flags_contains(5); // true (Active | Deleted)
// Invalid combinations
bool invalid1 = magic_enum::enum_flags_contains(static_cast<Status>(0)); // false
bool invalid2 = magic_enum::enum_flags_contains(8); // false (No flag for bit 8)
std::cout << std::boolalpha << valid1 << " " << invalid2 << std::endl;
return 0;
}
Validating String Representations
You can also validate if a string correctly names one or more flags.
#include <magic_enum/magic_enum_flags.hpp>
#include <iostream>
#include <string_view>
enum class Option { One = 1, Two = 2 };
template <>
struct magic_enum::customize::enum_range<Option> {
static constexpr bool is_flags = true;
};
int main() {
// Valid string combinations
bool v1 = magic_enum::enum_flags_contains<Option>("One"); // true
bool v2 = magic_enum::enum_flags_contains<Option>("One|Two"); // true
// Case-insensitive validation using a custom predicate
bool v3 = magic_enum::enum_flags_contains<Option>("one|TWO", [](char lhs, char rhs) {
return std::tolower(static_cast<unsigned char>(lhs)) == std::tolower(static_cast<unsigned char>(rhs));
}); // true
// Invalid strings
bool v4 = magic_enum::enum_flags_contains<Option>("Three"); // false
bool v5 = magic_enum::enum_flags_contains<Option>(""); // false
return 0;
}
Troubleshooting and Constraints
- Zero Values:
enum_flags_namereturns an empty string for0, andenum_flags_containsreturnsfalsefor0. In magic_enum,0is treated as "no flags set" rather than a valid flag itself. - Reflection Range: If a bitwise combination includes a bit that does not correspond to any named enumerator within the reflected range,
enum_flags_namereturns an empty string andenum_flags_containsreturnsfalse. - Header Requirement: All flag-related functions require including
magic_enum/magic_enum_flags.hpp. - Bitwise Operators: To use
operator|oroperator&with scoped enums, you must bring them into scope withusing namespace magic_enum::bitwise_operators;.