A header-only C++17 library for enum reflection, without registration macros or boilerplate.
-
Basic
#include <magic_enum/magic_enum.hpp> #include <iostream> enum class Color { RED = -10, BLUE = 0, GREEN = 10 }; int main() { Color c1 = Color::RED; std::cout << magic_enum::enum_name(c1) << std::endl; // RED return 0; }
-
Enum value to string
Color color = Color::RED; auto color_name = magic_enum::enum_name(color); // color_name -> "RED"
-
String to enum value
std::string color_name{"GREEN"}; auto color = magic_enum::enum_cast<Color>(color_name); if (color.has_value()) { // color.value() -> Color::GREEN } // case insensitive enum_cast auto color_case_insensitive = magic_enum::enum_cast<Color>(color_name, magic_enum::case_insensitive); // enum_cast with BinaryPredicate auto color_with_predicate = magic_enum::enum_cast<Color>(color_name, [](char lhs, char rhs) { return std::tolower(static_cast<unsigned char>(lhs)) == std::tolower(static_cast<unsigned char>(rhs)); }); // enum_cast with default auto color_or_default = magic_enum::enum_cast<Color>(color_name).value_or(Color::RED); -
Integer to enum value
int color_integer = 0; auto color = magic_enum::enum_cast<Color>(color_integer); if (color.has_value()) { // color.value() -> Color::BLUE } auto color_or_default = magic_enum::enum_cast<Color>(123).value_or(Color::RED);
-
Indexed access to enum value
std::size_t i = 0; Color color = magic_enum::enum_value<Color>(i); // color -> Color::RED
-
Enum value sequence
constexpr auto colors = magic_enum::enum_values<Color>(); // colors -> {Color::RED, Color::BLUE, Color::GREEN} // colors[0] -> Color::RED
-
Number of enum values
constexpr std::size_t color_count = magic_enum::enum_count<Color>(); // color_count -> 3
-
Enum value to integer
Color color = Color::RED; auto color_integer = magic_enum::enum_integer(color); // or magic_enum::enum_underlying(color); // color_integer -> -10
-
Enum name sequence
constexpr auto color_names = magic_enum::enum_names<Color>(); // color_names -> {"RED", "BLUE", "GREEN"} // color_names[0] -> "RED"
-
Enum entry sequence
constexpr auto color_entries = magic_enum::enum_entries<Color>(); // color_entries -> {{Color::RED, "RED"}, {Color::BLUE, "BLUE"}, {Color::GREEN, "GREEN"}} // color_entries[0].first -> Color::RED // color_entries[0].second -> "RED"
-
Enum fusion for multi-level switch/case statements
switch (magic_enum::enum_fuse(color, direction).value()) { case magic_enum::enum_fuse(Color::RED, Directions::Up).value(): // ... case magic_enum::enum_fuse(Color::BLUE, Directions::Down).value(): // ... // ... }
-
Runtime enum value as constexpr constant
Color color = Color::RED; magic_enum::enum_switch([](auto val) { constexpr Color c_color = val; // ... }, color);
-
Iterate over enum values as constexpr constants
magic_enum::enum_for_each<Color>([](auto val) { constexpr Color c_color = val; // ... });
-
Move through enum values
magic_enum::enum_next_value(Color::RED); // -> optional containing Color::BLUE magic_enum::enum_prev_value_circular(Color::RED); // -> Color::GREEN
-
Check whether enum contains value
magic_enum::enum_contains(Color::GREEN); // -> true magic_enum::enum_contains<Color>(0); // -> true magic_enum::enum_contains<Color>(123); // -> false magic_enum::enum_contains<Color>("GREEN"); // -> true magic_enum::enum_contains<Color>("fda"); // -> false
-
Check whether value can be reflected
magic_enum::enum_reflected(Color::GREEN); // -> true magic_enum::enum_reflected<Color>(1); // -> true, but not an enumerator
-
Enum index in sequence
constexpr auto color_index = magic_enum::enum_index(Color::BLUE); // color_index.value() -> 1 // color_index.has_value() -> true
-
Flag operations
enum Directions : std::uint64_t { Left = 1, Down = 2, Up = 4, Right = 8, }; template <> struct magic_enum::customize::enum_range<Directions> { static constexpr bool is_flags = true; }; MAGIC_ENUM_DEFINE_BITWISE_OPERATORS(Directions); // From <magic_enum/magic_enum_bitwise.hpp>. magic_enum::enum_flags_name(Directions::Up | Directions::Right); // -> "Up|Right" magic_enum::enum_flags_name(Directions::Up | Directions::Right, ','); // -> "Up,Right" magic_enum::enum_flags_contains(Directions::Up | Directions::Right); // -> true magic_enum::enum_flags_cast<Directions>(3).value(); // -> Directions::Left|Directions::Down magic_enum::enum_flags_cast<Directions>("Left,Down", ',').value(); // -> Directions::Left|Directions::Down magic_enum::enum_flags_test(Directions::Up | Directions::Right, Directions::Up); // -> true magic_enum::enum_flags_test_any(Directions::Left | Directions::Down, Directions::Down | Directions::Right); // -> true magic_enum::is_flags_v<Directions>; // -> true
-
Enum type name
Color color = Color::RED; auto type_name = magic_enum::enum_type_name<decltype(color)>(); // type_name -> "Color"
-
I/O stream operators for enums
#include <magic_enum/magic_enum_iostream.hpp> enum class Color { RED, GREEN, BLUE }; MAGIC_ENUM_DEFINE_IOSTREAM_OPERATORS(Color); // Operators for Color only, no using needed. Color color = Color::BLUE; std::cout << color << std::endl; // "BLUE" std::cin >> color;
-
Bitwise operators for enums
#include <magic_enum/magic_enum_bitwise.hpp> enum class Flags { A = 1 << 0, B = 1 << 1, C = 1 << 2, D = 1 << 3 }; MAGIC_ENUM_DEFINE_BITWISE_OPERATORS(Flags); // Defines ~, |, &, ^, |=, &=, ^= for Flags. Flags flags = Flags::A | (Flags::B & ~Flags::C);
For a nested enum, use
MAGIC_ENUM_DEFINE_FRIEND_*inside its class. Prefer these macros to operator namespaces, which affect every enum in scope. See operator namespace risks. -
Formatting
#include <format> #include <magic_enum/magic_enum_format.hpp> std::format("{}", Color::RED); // -> "RED" std::format("{}", Color{42}); // -> "42"
For
{fmt}, include it beforemagic_enum_format.hpp. -
Unscoped enum trait
enum color { red, green, blue }; enum class direction { left, right }; static_assert(magic_enum::is_unscoped_enum_v<color>); static_assert(!magic_enum::is_unscoped_enum_v<direction>);
-
Scoped enum trait
enum color { red, green, blue }; enum class direction { left, right }; static_assert(!magic_enum::is_scoped_enum_v<color>); static_assert(magic_enum::is_scoped_enum_v<direction>);
-
Compile-time enum value to string, without the
enum_rangelimit.constexpr Color color = Color::BLUE; constexpr auto color_name = magic_enum::enum_name<color>(); // color_name -> "BLUE"
-
containers::arrayarray container for enums.// In enum_values order: RED, BLUE, GREEN. constexpr auto color_rgb_values = magic_enum::containers::make_array<Color>(RGB{255, 0, 0}, RGB{0, 0, 255}, RGB{0, 255, 0}); magic_enum::containers::array<Color, RGB> color_rgb_array {}; color_rgb_array[Color::RED] = {255, 0, 0}; color_rgb_array[Color::GREEN] = {0, 255, 0}; color_rgb_array[Color::BLUE] = {0, 0, 255}; magic_enum::containers::get<Color::BLUE>(color_rgb_array); // -> RGB{0, 0, 255}
-
containers::bitsetbitset container for enums.constexpr magic_enum::containers::bitset<Color> color_bitset {Color::RED, Color::GREEN}; color_bitset.test(Color::RED); // -> true color_bitset.test(Color::BLUE); // -> false std::uint8_t incoming = 0b00000011; auto raw_bitset = magic_enum::containers::bitset<Color> {magic_enum::containers::raw_access, incoming};
-
containers::setset container for enums.auto color_set = magic_enum::containers::set<Color>(); bool empty = color_set.empty(); // empty -> true color_set.insert(Color::GREEN); color_set.insert(Color::BLUE); color_set.insert(Color::RED); std::size_t size = color_set.size(); // size -> 3 using color_name_set = magic_enum::containers::set<Color, magic_enum::containers::name_less<>>; color_name_set colors_by_name {Color::RED, Color::GREEN, Color::BLUE};
-
static_assert(std::is_same_v<magic_enum::underlying_type<Color>::type, int>); static_assert(std::is_same_v<magic_enum::underlying_type_t<Color>, int>);
-
Copy the required headers from
include/magic_enumor a release archive.magic_enum_all.hppincludes all public headers. -
With CMake 3.22+, use
add_subdirectoryorfind_package(magic_enum CONFIG REQUIRED), then linkmagic_enum::magic_enum. -
Fetch sources with CMake
FetchContentor CPM.cmake. Release tags usevx.y.zformat. -
Use Bazel with
MODULE.bazelorhttp_archive. The target is@magic_enum//:magic_enum. -
Use ROS with
<depend>magic_enum</depend>inpackage.xml, then linkmagic_enum::magic_enum. -
CMake targets:
magic_enum::magic_enumis the header-only target.magic_enum::magic_enum_moduleis the C++20 module target. Enable it withMAGIC_ENUM_USE_MODULES=ON. CMake 3.28+ is required.
Build the module target:
cmake -S . -B build -G Ninja -DMAGIC_ENUM_USE_MODULES=ON cmake --build buildLink the module target:
find_package(magic_enum CONFIG REQUIRED) target_link_libraries(your_executable PRIVATE magic_enum::magic_enum_module) set_target_properties(your_executable PROPERTIES CXX_EXTENSIONS OFF CXX_SCAN_FOR_MODULES ON)
Import the module:
import magic_enum; enum class Color { RED, GREEN, BLUE }; auto name = magic_enum::enum_name(Color::RED); // "RED"
Use either the headers or the module in the whole program. Build and use an installed module with the same compiler, standard library and C++ standard. pkg-config provides only the header-only target.
Optional settings:
MAGIC_ENUM_MODULE_WITH_FMT=ONenables{fmt}throughfmt::fmt. The{fmt}module is not supported.MAGIC_ENUM_MODULE_IMPORT_STD=ONenablesimport std. It requires C++23+, CMake 3.31+ and a compatible toolchain.
- Clang/LLVM >= 9
- MSVC >= 19.20 / Visual Studio >= 2019 (16.0)
- Xcode >= 11
- GCC >= 9
C++26 reflection is selected automatically when available. See limitations.