Skip to content

About

Static reflection for enums (to string, from string, iteration) for modern C++, work with any enum type without any macro or boilerplate code

Topics

Resources

Security policy

Stars

6.2k stars

Watchers

64 watching

Forks

Repository files navigation

Github releases Conan package Vcpkg package Build2 package Meson wrap License Compiler explorer OpenSSF Scorecard

Magic Enum C++

A header-only C++17 library for enum reflection, without registration macros or boilerplate.

Documentation

  • 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 before magic_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_range limit.

    constexpr Color color = Color::BLUE;
    constexpr auto color_name = magic_enum::enum_name<color>();
    // color_name -> "BLUE"
  • containers::array array 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::bitset bitset 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::set set 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};
  • Underlying type

    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>);

Integration

  • Copy the required headers from include/magic_enum or a release archive. magic_enum_all.hpp includes all public headers.

  • With CMake 3.22+, use add_subdirectory or find_package(magic_enum CONFIG REQUIRED), then link magic_enum::magic_enum.

  • Use vcpkg, Conan, Build2, or Meson.

  • Fetch sources with CMake FetchContent or CPM.cmake. Release tags use vx.y.z format.

  • Use Bazel with MODULE.bazel or http_archive. The target is @magic_enum//:magic_enum.

  • Use ROS with <depend>magic_enum</depend> in package.xml, then link magic_enum::magic_enum.

  • CMake targets:

    • magic_enum::magic_enum is the header-only target.
    • magic_enum::magic_enum_module is the C++20 module target. Enable it with MAGIC_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 build

    Link 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=ON enables {fmt} through fmt::fmt. The {fmt} module is not supported.
    • MAGIC_ENUM_MODULE_IMPORT_STD=ON enables import std. It requires C++23+, CMake 3.31+ and a compatible toolchain.

Compiler compatibility

  • 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.

Licensed under the MIT License

About

Static reflection for enums (to string, from string, iteration) for modern C++, work with any enum type without any macro or boilerplate code

Topics

Resources

Security policy

Stars

6.2k stars

Watchers

64 watching

Forks

Releases

Packages

Used by

Contributors

Languages