Iterate, dispatch, and store enum values
When you need to perform operations across all members of an enumeration or store data associated with specific enum keys, standard C++ requires manual maintenance of arrays and switch statements. magic_enum provides utilities to automate these patterns, ensuring that your logic stays in sync with your enum definitions.
Iterating Over Enum Values
The magic_enum::enum_for_each function in magic_enum/magic_enum_utility.hpp allows you to execute a callable for every value in an enum at compile time. 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 a magic_enum::enum_constant<V>.
#include <iostream>
#include <string>
#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) {
constexpr Color c = val;
std::cout << magic_enum::enum_name(c) << " ";
});
// Output: Red Green Blue
}
Collecting Results
If the callable returns a value, enum_for_each collects these into a container. If all return types are identical, it returns a std::array. If they differ, it returns a std::tuple.
#include <array>
#include <string_view>
#include "magic_enum/magic_enum.hpp"
#include "magic_enum/magic_enum_utility.hpp"
constexpr auto color_names = magic_enum::enum_for_each<Color>([](auto val) {
return magic_enum::enum_name<val>();
});
// color_names is std::array<std::string_view, 3>
Type-Safe Dispatching
The magic_enum::enum_switch function in magic_enum/magic_enum_switch.hpp provides a functional alternative to the switch statement. It maps a runtime enum value to a compile-time constant within a visitor.
Handling Specific Cases
You can use a visitor (like a lambda or an overloaded helper) to handle specific values. It is highly recommended to specify an explicit result type to ensure safety.
#include <iostream>
#include <string>
#include "magic_enum/magic_enum.hpp"
#include "magic_enum/magic_enum_switch.hpp"
enum class Color { Red, Green, Blue };
std::string get_description(Color c) {
return magic_enum::enum_switch<std::string>([](auto val) -> std::string {
constexpr Color color = val;
if constexpr (color == Color::Red) {
return "The color of fire.";
} else {
return std::string(magic_enum::enum_name(color));
}
}, c);
}
Safety and Default Values
If enum_switch is called with an invalid enum value (e.g., a casted integer that isn't a member), it returns a default-constructed instance of the result type. By providing a third argument, you can specify a custom default value.
#include <cassert>
#include <string>
#include "magic_enum/magic_enum.hpp"
#include "magic_enum/magic_enum_switch.hpp"
void check_switch(Color c) {
// Returns empty string if c is invalid
auto res = magic_enum::enum_switch<std::string>([](auto val) {
return std::string(magic_enum::enum_name<val>());
}, c);
// Returns "Unknown" if c is invalid
auto res_with_default = magic_enum::enum_switch<std::string>([](auto val) {
return std::string(magic_enum::enum_name<val>());
}, c, "Unknown");
}
Enum-Aware Containers
The magic_enum/magic_enum_containers.hpp header provides containers that use enums as primary keys, offering better type safety and performance than std::map for enum-indexed data.
Enum-Indexed Arrays
magic_enum::containers::array<E, V> is a wrapper around std::array<V, enum_count<E>()>. It allows you to use enum values directly for indexing.
#include <iostream>
#include "magic_enum/magic_enum.hpp"
#include "magic_enum/magic_enum_containers.hpp"
enum class Color { Red, Green, Blue };
void use_array() {
magic_enum::containers::array<Color, int> scores{{10, 20, 30}};
// Access via enum value
scores[Color::Green] = 25;
// Bounds-checked access throws std::out_of_range for invalid enums
try {
scores.at(static_cast<Color>(99)) = 0;
} catch (const std::out_of_range& e) {
std::cerr << e.what() << std::endl;
}
// Compile-time access via get
int red_score = magic_enum::containers::get<Color::Red>(scores);
}
Enum Sets
magic_enum::containers::set<E> provides a set-like interface for enums, internally optimized using a bitset. It supports standard operations like insert, erase, and contains.
#include <iostream>
#include "magic_enum/magic_enum.hpp"
#include "magic_enum/magic_enum_containers.hpp"
enum class Color { Red, Green, Blue };
void use_set() {
magic_enum::containers::set<Color> active_colors {Color::Red, Color::Blue};
if (active_colors.contains(Color::Red)) {
std::cout << "Red is active" << std::endl;
}
active_colors.insert(Color::Green);
active_colors.erase(Color::Blue);
std::cout << "Set size: " << active_colors.size() << std::endl; // Prints 2
}
Internally, magic_enum::containers::set uses magic_enum::containers::bitset to store presence. This makes operations like contains extremely fast (O(1)) compared to std::set (O(log N)).