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 format these combinations into delimited strings and validate whether a bitmask consists only of recognized flags.

To use these features, you must opt-in your enum by specializing magic_enum::customize::enum_range and setting is_flags to true.

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

enum class Color : int { RED = 1, GREEN = 2, BLUE = 4 };

// Enable flag-specific logic for this 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 scoped enums

auto flags = Color::RED | Color::BLUE;

// 1. Get string representation of combined flags
// Returns "RED|BLUE"
std::cout << magic_enum::enum_flags_name(flags) << std::endl;

// 2. Validate if a value is a valid combination of flags
bool is_valid = magic_enum::enum_flags_contains(flags); // true
bool is_invalid = magic_enum::enum_flags_contains(static_cast<Color>(8)); // false

return 0;
}

Formatting flag combinations

The magic_enum::enum_flags_name function produces a string containing the names of all set flags, separated by a delimiter. By default, it uses the pipe character (|), but you can provide a custom separator as the second argument.

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

enum class Permission { Read = 1, Write = 2, Execute = 4 };

template <>
struct magic_enum::customize::enum_range<Permission> {
static constexpr bool is_flags = true;
};

void format_example() {
using namespace magic_enum::bitwise_operators;
auto p = Permission::Read | Permission::Write;

// Default separator: "Read|Write"
std::string default_sep = magic_enum::enum_flags_name(p);

// Custom separator: "Read + Write"
std::string custom_sep = magic_enum::enum_flags_name(p, '+');
}

If the value contains bits that do not correspond to any defined enumerator, magic_enum::enum_flags_name returns an empty string.

Validating flag values

The magic_enum::enum_flags_contains function checks if a value (whether passed as the enum type, the underlying integer, or a string) represents a valid set of flags defined in the enum.

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

enum class Animal { Cat = 1, Dog = 2, Bird = 4 };

template <>
struct magic_enum::customize::enum_range<Animal> {
static constexpr bool is_flags = true;
};

void validation_example() {
// Check by enum value
bool v1 = magic_enum::enum_flags_contains(static_cast<Animal>(3)); // true (Cat | Dog)

// Check by underlying integer
bool v2 = magic_enum::enum_flags_contains<Animal>(5); // true (Cat | Bird)

// Check by string representation
bool v3 = magic_enum::enum_flags_contains<Animal>("Cat|Dog"); // true
bool v4 = magic_enum::enum_flags_contains<Animal>("Cat|Fish"); // false
}

Handling the zero value

In magic_enum, a value of 0 is not considered a valid flag combination by the enum_flags_* APIs.

  • magic_enum::enum_flags_name returns an empty string for 0.
  • magic_enum::enum_flags_contains returns false for 0.

If your enum requires a "None" or "Empty" state represented by 0, you should handle it separately or use the standard magic_enum::enum_name if you have explicitly defined an enumerator for 0.

Requirements for bitwise operations

To combine scoped enum values using operator| (as seen in the examples above), you must make the magic_enum bitwise operators visible in your scope:

using namespace magic_enum::bitwise_operators;

This enables |, &, ~, ^, |=, &=, and ^= for any enum type, allowing you to treat them as bitfields without manual casting to underlying types.