Skip to main content

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;
}