Inspect and validate flag enums
To inspect and validate bitwise combinations of enum values in magic_enum, you must first mark the enum as a flags enum by specializing magic_enum::customize::enum_range. Once configured, you can use enum_flags_name to generate string representations of combined flags and enum_flags_contains to verify if a specific value, integer, or string represents a valid set of flags.
Configure and Format Flag Enums
To enable flag-specific logic, specialize magic_enum::customize::enum_range for your enum type and set is_flags = true. This allows enum_flags_name to decompose a bitwise-ORed value into its constituent names separated by a delimiter (defaulting to |).
#include <iostream>
#include <string>
#include <magic_enum/magic_enum_flags.hpp>
enum class Color { RED = 1, GREEN = 2, BLUE = 4 };
// Mark the enum as a flags enum
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 enums
Color c = Color::RED | Color::BLUE;
// Get string representation: "RED|BLUE"
auto name = magic_enum::enum_flags_name(c);
if (!name.empty()) {
std::cout << "Flags: " << name << std::endl;
}
// Returns empty string for values containing undefined bits
auto invalid = magic_enum::enum_flags_name(static_cast<Color>(8));
std::cout << "Invalid is empty: " << std::boolalpha << invalid.empty() << std::endl;
return 0;
}
Validate Flag Combinations
The enum_flags_contains function checks if a value is a valid combination of the flags defined in the enum. It returns false if the value contains any bits that are not part of a named enumerator, or if the value is 0 (as 0 is not considered a flag).
#include <iostream>
#include <magic_enum/magic_enum_flags.hpp>
enum class Permissions { Read = 1, Write = 2, Execute = 4 };
template <>
struct magic_enum::customize::enum_range<Permissions> {
static constexpr bool is_flags = true;
};
int main() {
using namespace magic_enum::bitwise_operators;
// Validate enum values
bool v1 = magic_enum::enum_flags_contains(Permissions::Read | Permissions::Write); // true
bool v2 = magic_enum::enum_flags_contains(static_cast<Permissions>(10)); // false (8 is missing)
// Validate integer values (requires explicit template argument)
bool v3 = magic_enum::enum_flags_contains<Permissions>(3); // true (1 | 2)
bool v4 = magic_enum::enum_flags_contains<Permissions>(0); // false
std::cout << "Valid (3): " << v3 << ", Valid (0): " << v4 << std::endl;
return 0;
}
Validate String Representations
You can also validate whether a string correctly represents a combination of flags. This is useful for parsing user input or configuration files. Like the integer overload, the string overload of enum_flags_contains requires an explicit template argument.
#include <iostream>
#include <string_view>
#include <cctype>
#include <magic_enum/magic_enum_flags.hpp>
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() {
// Standard validation
bool s1 = magic_enum::enum_flags_contains<Status>("Active|Pending"); // true
bool s2 = magic_enum::enum_flags_contains<Status>("Active|Unknown"); // false
// Case-insensitive validation using a custom predicate
auto ignore_case = [](char lhs, char rhs) {
return std::tolower(static_cast<unsigned char>(lhs)) == std::tolower(static_cast<unsigned char>(rhs));
};
bool s3 = magic_enum::enum_flags_contains<Status>("active|PENDING", ignore_case); // true
std::cout << "Valid string: " << s1 << ", Case-insensitive: " << s3 << std::endl;
return 0;
}