Skip to main content

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_name returns an empty string for 0, and enum_flags_contains returns false for 0. In magic_enum, 0 is 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_name returns an empty string and enum_flags_contains returns false.
  • Header Requirement: All flag-related functions require including magic_enum/magic_enum_flags.hpp.
  • Bitwise Operators: To use operator| or operator& with scoped enums, you must bring them into scope with using namespace magic_enum::bitwise_operators;.