Convert Figma logo to code with AI

Neargye logomagic_enum

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

6,195
567
6,195
17

Top Related Projects

2,360

Nameof operator for modern C++, simply obtain the name of a variable, type, function, macro, and enum

Quick Overview

Neargye/magic_enum is a C++17 header-only library that provides a convenient way to convert between enums and strings, without the need for manual conversion code. It allows you to use enums in a more flexible and powerful way, enabling features like enum iteration, enum-to-string conversion, and string-to-enum conversion.

Pros

  • Simplicity: The library is header-only and easy to integrate into your project, with no external dependencies.
  • Performance: The library uses compile-time reflection, resulting in fast and efficient enum conversions.
  • Flexibility: Supports a wide range of enum types, including scoped enums, enum classes, and traditional enums.
  • Extensibility: Allows you to customize the string representation of your enums, if needed.

Cons

  • Compiler Support: The library requires a C++17 compliant compiler, which may not be available on all platforms.
  • Compile-time Overhead: The extensive use of compile-time reflection can increase compilation times, especially for larger projects.
  • Limited Enum Size: The library has a maximum limit of 1024 enum values, which may be a constraint for some use cases.
  • No Runtime Error Handling: The library does not provide any runtime error handling for invalid enum-to-string or string-to-enum conversions.

Code Examples

// Enum class example
enum class Color { Red, Green, Blue };

// Enum-to-string conversion
std::cout << magic_enum::enum_name(Color::Red) << std::endl; // Output: "Red"

// String-to-enum conversion
Color color = magic_enum::enum_cast<Color>("Green").value(); // Color::Green

// Enum iteration
for (const auto color : magic_enum::enum_values<Color>()) {
    std::cout << magic_enum::enum_name(color) << " ";
} // Output: "Red Green Blue "
// Scoped enum example
enum class Fruit : uint8_t { Apple, Banana, Orange };

// Custom string representation
template <>
struct magic_enum::customize::enum_name<Fruit> {
    static constexpr auto value(Fruit fruit) noexcept {
        switch (fruit) {
            case Fruit::Apple: return "red apple";
            case Fruit::Banana: return "yellow banana";
            case Fruit::Orange: return "orange fruit";
        }
    }
};

std::cout << magic_enum::enum_name(Fruit::Apple) << std::endl; // Output: "red apple"
// Traditional enum example
enum Animal { Dog, Cat, Bird };

// Enum-to-integer conversion
int dog_value = magic_enum::enum_integer(Animal::Dog); // 0

Getting Started

To use the Neargye/magic_enum library, follow these steps:

  1. Download the latest release of the library from the GitHub repository.
  2. Include the magic_enum.hpp header file in your C++ project:
#include <magic_enum.hpp>
  1. Start using the library's features, such as enum-to-string conversion, string-to-enum conversion, and enum iteration:
enum class Color { Red, Green, Blue };

std::cout << magic_enum::enum_name(Color::Red) << std::endl; // Output: "Red"
Color color = magic_enum::enum_cast<Color>("Green").value(); // Color::Green

for (const auto c : magic_enum::enum_values<Color>()) {
    std::cout << magic_enum::enum_name(c) << " ";
} // Output: "Red Green Blue "

That's it! The Neargye/magic_enum library is now ready to use in your C++17 project.

Competitor Comparisons

2,360

Nameof operator for modern C++, simply obtain the name of a variable, type, function, macro, and enum

Pros of nameof

  • Broader scope: Works with functions, variables, and types, not just enums
  • Simpler implementation: Doesn't require complex template metaprogramming
  • Potentially faster compile times due to simpler implementation

Cons of nameof

  • Less feature-rich for enum operations
  • Doesn't provide automatic string conversion for enum values
  • Limited to compile-time name retrieval, unlike magic_enum's runtime capabilities

Code Comparison

nameof:

const char* name = NAMEOF(someVariable);
const char* func = NAMEOF(&MyClass::myMethod);

magic_enum:

enum class Color { Red, Green, Blue };
auto color_name = magic_enum::enum_name(Color::Red);
auto colors = magic_enum::enum_names<Color>();

Both libraries provide compile-time name retrieval, but magic_enum focuses on enums with more advanced features. nameof offers a broader scope for naming different C++ entities. magic_enum provides more comprehensive enum operations, while nameof is simpler and potentially faster to compile. The choice between them depends on specific project needs, particularly whether advanced enum functionality is required or if naming other C++ entities is more important.

Convert Figma logo designs to code with AI

Visual Copilot

Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.

Try Visual Copilot

README

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

Magic Enum C++

Header-only C++17 library provides static reflection for enums, work with any enum type without any macro or boilerplate code.

Documentation

Features & Examples

  • 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
    
  • 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;
    };
    using namespace magic_enum::bitwise_operators; // Use with care; operators are enabled for all enums.
    
    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

    using magic_enum::iostream_operators::operator<<; // out-of-the-box ostream operators for enums.
    Color color = Color::BLUE;
    std::cout << color << std::endl; // "BLUE"
    
    using magic_enum::iostream_operators::operator>>; // out-of-the-box istream operators for enums.
    Color color;
    std::cin >> color;
    
  • Bitwise operators for enums

    enum class Flags { A = 1 << 0, B = 1 << 1, C = 1 << 2, D = 1 << 3 };
    using namespace magic_enum::bitwise_operators; // Use with care; operators are enabled for all enums.
    // Support operators: ~, |, &, ^, |=, &=, ^=.
    Flags flags = Flags::A | (Flags::B & ~Flags::C);
    
  • Formatting

    #include <format>
    #include <magic_enum/magic_enum_format.hpp>
    
    std::format("{}", Color::RED); // -> "RED"
    std::format("{}", Color{42});  // -> "42"
    

    Include {fmt} before magic_enum_format.hpp to enable {fmt} formatter support.

  • Unscoped enum trait

    enum color { red, green, blue };
    enum class direction { left, right };
    
    magic_enum::is_unscoped_enum_v<color> -> true
    magic_enum::is_unscoped_enum_v<direction> -> false
    
  • Scoped enum trait

    enum color { red, green, blue };
    enum class direction { left, right };
    
    magic_enum::is_scoped_enum_v<color> -> false
    magic_enum::is_scoped_enum_v<direction> -> true
    
  • Compile-time enum value to string. This overload compiles faster and is not restricted by enum_range limitation.

    constexpr Color color = Color::BLUE;
    constexpr auto color_name = magic_enum::enum_name<color>();
    // color_name -> "BLUE"
    
  • containers::array array container for enums.

    constexpr auto color_rgb_values = magic_enum::containers::make_array<Color>(RGB{255, 0, 0}, RGB{0, 255, 0}, RGB{0, 0, 255});
    
    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

    magic_enum::underlying_type<Color>::type -> int
    magic_enum::underlying_type_t<Color> -> int
    

Integration

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

  • Use CMake with 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; 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"
    

    Do not use #include <magic_enum/...> and import magic_enum; in the same program. Use the same compiler, standard library, and C++ standard when building and consuming an installed module. The pkg-config package supports only the header-only target.

    Optional settings:

    • Set MAGIC_ENUM_MODULE_WITH_FMT=ON to enable {fmt} support through fmt::fmt. It is disabled by default. The {fmt} C++ module is not supported.
    • Set MAGIC_ENUM_MODULE_IMPORT_STD=ON to enable import std support. This requires a compatible CMake toolchain.

Header-only compiler compatibility

  • Clang/LLVM >= 5
  • MSVC++ >= 15.3 / Visual Studio >= 2017
  • Xcode >= 10
  • GCC >= 9

C++26 reflection is selected automatically when available; see limitations.

Licensed under the MIT License