Skip to main content

Iterate, dispatch, and store enum values

When you need to perform operations on every member of an enumeration or map enum values to specific data, manual switch statements and standard containers like std::map can be verbose and inefficient. magic_enum provides specialized utilities and containers that leverage compile-time reflection to simplify these patterns.

Iterate over enum values

The magic_enum::enum_for_each function allows you to apply a callable to every value in an enumeration. This is useful for generating reports, initializing data structures, or performing batch operations.

Basic iteration

To perform a side-effect for each enum value, pass a lambda that accepts an auto parameter. This parameter is an instance of magic_enum::detail::enum_constant, which can be converted to the actual enum value by calling it as a function.

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

enum class Color { Red, Green, Blue };

void print_all_colors() {
magic_enum::enum_for_each<Color>([](auto val) {
// val is a compile-time constant wrapper.
// Use val() to get the actual enum value.
std::cout << magic_enum::enum_name(val()) << " ";
});
// Output: Red Green Blue
}

Transforming enums into arrays

If your lambda returns a value, magic_enum::enum_for_each collects these results into a std::array. This is a powerful way to build lookup tables at compile time.

#include <array>
#include <string_view>
#include <magic_enum/magic_enum.hpp>
#include <magic_enum/magic_enum_utility.hpp>

enum class Color { Red, Green, Blue };

constexpr auto color_names = magic_enum::enum_for_each<Color>([](auto val) {
return magic_enum::enum_name(val());
});

static_assert(color_names == std::array<std::string_view, 3>{"Red", "Green", "Blue"});

Dispatch with enum_switch

Traditional switch statements are prone to errors if you forget a break or fail to handle a new enum member. magic_enum::enum_switch provides a functional alternative that maps a runtime enum value to a compile-time constant inside a lambda.

Safe dispatching

When using enum_switch, you must specify a result type (e.g., std::string) to ensure that invalid or out-of-range enum values are handled safely. If the value is invalid, enum_switch returns a default-constructed instance of the result type.

#include <string>
#include <magic_enum/magic_enum.hpp>
#include <magic_enum/magic_enum_switch.hpp>

enum class Color { Red, Green, Blue };

std::string get_color_description(Color c) {
return magic_enum::enum_switch<std::string>(
[](auto val) -> std::string {
// Inside here, 'val' is a compile-time constant.
// You can use it in constexpr contexts.
constexpr Color color = val();
if constexpr (color == Color::Red) {
return "The color of fire";
} else {
return std::string{magic_enum::enum_name(color)};
}
},
c
);
}

Internally, magic_enum::enum_switch generates a series of checks (or a hash-based jump if enabled) to find the matching constant. If no match is found, it invokes a default result lambda, which returns Result{}.

Store values in enum-aware containers

The magic_enum::containers namespace provides data structures optimized for enums, found in magic_enum/magic_enum_containers.hpp.

Map data with array

The magic_enum::containers::array class is a wrapper around std::array that allows using enum values directly as indices. It provides the performance of a raw array with the type safety of an enum-based map.

#include <magic_enum/magic_enum_containers.hpp>

enum class Color { Red, Green, Blue };

struct RGB { int r, g, b; };

void use_color_map() {
magic_enum::containers::array<Color, RGB> color_values{{
{255, 0, 0}, // Red
{0, 255, 0}, // Green
{0, 0, 255} // Blue
}};

// Access using enum values
RGB red = color_values[Color::Red];

// .at() provides bounds checking against the enum's reflected range
RGB green = color_values.at(Color::Green);
}

Manage sets of enums

The magic_enum::containers::set class stores a collection of unique enum values. It is implemented using a bitset internally, making it extremely memory-efficient and fast for membership checks.

#include <magic_enum/magic_enum_containers.hpp>

enum class Color { Red, Green, Blue };

void manage_palette() {
magic_enum::containers::set<Color> palette;

palette.insert(Color::Red);
palette.insert(Color::Blue);

if (palette.contains(Color::Red)) {
// ...
}

// Iteration follows the order of enum values
for (Color c : palette) {
// Iterates over Red, then Blue
}
}

The set uses magic_enum::containers::detail::indexing to map enum values to bit positions. By default, it uses the reflected order of the enum, but you can provide a custom comparator (like magic_enum::containers::name_less) to change the iteration order.