Inspect and validate flag enums
When you work with bitmask-style enums in C++, standard string conversion and validation often fail because they expect a single enumerator value. magic_enum provides specialized APIs in magic_enum/magic_enum_flags.hpp to handle these bitwise combinations, allowing you to format multiple active flags into a single string and validate whether a bitmask consists only of recognized flags.
Enable flag support for an enum
To use flag-specific APIs, you must opt-in by specializing magic_enum::customize::enum_range for your enum type and setting is_flags to true. This tells magic_enum to treat the enum as a bitmask during reflection.
#include <iostream>
#include <magic_enum/magic_enum_flags.hpp>
enum class Color : int {
RED = 1 << 0,
GREEN = 1 << 1,
BLUE = 1 << 2
};
// Opt-in to flag support
template <>
struct magic_enum::customize::enum_range<Color> {
static constexpr bool is_flags = true;
};
int main() {
// Bring bitwise operators into scope for scoped enums
using namespace magic_enum::bitwise_operators;
Color color = Color::RED | Color::BLUE;
// enum_flags_name returns a string of joined flag names
// Output: "RED|BLUE"
std::cout << magic_enum::enum_flags_name(color) << std::endl;
return 0;
}
Validate flag combinations
You can verify if a specific value (whether an enum instance, an underlying integer, or a string) represents a valid combination of the defined flags using magic_enum::enum_flags_contains. A combination is valid if every set bit corresponds to a named enumerator in the enum definition.
When passing an integer or a string to enum_flags_contains, you must explicitly provide the enum type as a template argument.
#include <iostream>
#include <cassert>
#include <magic_enum/magic_enum_flags.hpp>
enum class Permission : int {
Read = 1,
Write = 2,
Execute = 4
};
template <>
struct magic_enum::customize::enum_range<Permission> {
static constexpr bool is_flags = true;
};
int main() {
using namespace magic_enum::bitwise_operators;
// 1. Validate enum instances
Permission p = Permission::Read | Permission::Write;
bool isValid = magic_enum::enum_flags_contains(p); // true
// 2. Validate underlying integers (requires explicit template argument)
bool isIntValid = magic_enum::enum_flags_contains<Permission>(5); // true (Read | Execute)
bool isIntInvalid = magic_enum::enum_flags_contains<Permission>(8); // false (no flag for 8)
// 3. Validate string representations (requires explicit template argument)
bool isStrValid = magic_enum::enum_flags_contains<Permission>("Read|Write"); // true
assert(isValid && isIntValid && !isIntInvalid && isStrValid);
return 0;
}
Handle zero values and custom delimiters
By default, magic_enum::enum_flags_name uses the pipe character (|) as a separator. You can provide a custom character as the second argument. Note that magic_enum does not consider 0 a valid flag value; enum_flags_name returns an empty string for 0, and enum_flags_contains returns false.
#include <iostream>
#include <string>
#include <magic_enum/magic_enum_flags.hpp>
enum class Status : int {
Active = 1,
Pending = 2,
Alert = 4
};
template <>
struct magic_enum::customize::enum_range<Status> {
static constexpr bool is_flags = true;
};
int main() {
using namespace magic_enum::bitwise_operators;
Status s = Status::Active | Status::Alert;
// Use a custom separator
// Output: "Active, Alert"
std::string formatted = magic_enum::enum_flags_name(s, ',');
std::cout << formatted << std::endl;
// Zero value behavior
Status none = static_cast<Status>(0);
std::cout << "Zero name: '" << magic_enum::enum_flags_name(none) << "'" << std::endl; // Empty
std::cout << "Zero valid: " << std::boolalpha << magic_enum::enum_flags_contains(none) << std::endl; // false
return 0;
}