Skip to main content

Inspect and validate flag enums

When you work with bitmask enums in C++, standard string conversion and validation often fail because they expect a single enumerator value rather than a bitwise combination. magic_enum provides specialized APIs in magic_enum/magic_enum_flags.hpp to handle these scenarios, allowing you to format combined flags as strings and validate whether a bitmask contains only recognized flags.

Define a flag enum

To use flag-specific APIs, you must explicitly mark your enum as a bitmask by specializing magic_enum::customize::enum_range and setting is_flags to true.

#include <magic_enum/magic_enum_flags.hpp>
#include <iostream>
#include <cstdint>

enum class AnimalFlags : std::uint64_t {
HasClaws = 1 << 10,
CanFly = 1 << 20,
EatsFish = 1 << 30,
Endangered = std::uint64_t{1} << 40
};

// Required specialization to enable flag-based reflection
template <>
struct magic_enum::customize::enum_range<AnimalFlags> {
static constexpr bool is_flags = true;
};

Format combined flags as strings

The magic_enum::enum_flags_name function converts a bitwise combination of flags into a string representation. By default, it uses the | character as a separator.

#include <magic_enum/magic_enum_flags.hpp>
#include <iostream>

void print_flags(AnimalFlags flags) {
// Brings operator| into scope for enums
using namespace magic_enum::bitwise_operators;

// Returns "HasClaws|CanFly"
std::string name = magic_enum::enum_flags_name(flags);

if (!name.empty()) {
std::cout << "Flags: " << name << std::endl;
} else {
std::cout << "Invalid or empty flags" << std::endl;
}
}

int main() {
using namespace magic_enum::bitwise_operators;
print_flags(AnimalFlags::HasClaws | AnimalFlags::CanFly);
return 0;
}

Validate flag combinations

Use magic_enum::enum_flags_contains to verify if a value (whether an enum instance, an integer, or a string) represents a valid set of flags defined in your enum. A combination is considered valid only if every set bit corresponds to a named enumerator.

#include <magic_enum/magic_enum_flags.hpp>
#include <cassert>

void validate_examples() {
using namespace magic_enum::bitwise_operators;

// 1. Validate enum combinations
auto valid_combo = AnimalFlags::HasClaws | AnimalFlags::EatsFish;
assert(magic_enum::enum_flags_contains(valid_combo));

// 2. Validate from underlying integer
// 1073742848 is (1 << 10) | (1 << 30)
assert(magic_enum::enum_flags_contains<AnimalFlags>(1073742848));

// Invalid: contains bit (1 << 0) which is not defined in AnimalFlags
assert(!magic_enum::enum_flags_contains<AnimalFlags>(1073742849));

// 3. Validate from string
assert(magic_enum::enum_flags_contains<AnimalFlags>("HasClaws|CanFly"));
assert(!magic_enum::enum_flags_contains<AnimalFlags>("HasClaws|UnknownFlag"));
}

Common Pitfalls

  • Missing Specialization: If you do not set is_flags = true in magic_enum::customize::enum_range, enum_flags_name will return an empty string for any value that doesn't exactly match a single enumerator.
  • Zero Values: In magic_enum, a value of 0 is not considered a valid flag. magic_enum::enum_flags_contains(static_cast<MyEnum>(0)) returns false, and magic_enum::enum_flags_name returns an empty string for 0.
  • Bitwise Operators: Standard C++ does not provide bitwise operators for scoped enums. You must use using namespace magic_enum::bitwise_operators; to enable |, &, ~, and ^ for your enum types.
  • Invalid Bits: If a bitmask contains even one bit that does not correspond to a defined enumerator, magic_enum::enum_flags_name returns an empty string rather than a partial result.