magic_enum
Static reflection for enums (to string, from string, iteration) for modern C++, work with any enum type without any macro or boilerplate code
Top Related Projects
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:
- Download the latest release of the library from the GitHub repository.
- Include the
magic_enum.hppheader file in your C++ project:
#include <magic_enum.hpp>
- 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
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
designs to code with AI
Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.
Try Visual CopilotREADME
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}beforemagic_enum_format.hppto 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_rangelimitation.constexpr Color color = Color::BLUE; constexpr auto color_name = magic_enum::enum_name<color>(); // color_name -> "BLUE" -
containers::arrayarray 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::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}; -
magic_enum::underlying_type<Color>::type -> int magic_enum::underlying_type_t<Color> -> int
Integration
-
Copy required headers from
include/magic_enumor use release archive.magic_enum_all.hppincludes all public headers. -
Use CMake with
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; 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"Do not use
#include <magic_enum/...>andimport 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=ONto enable{fmt}support throughfmt::fmt. It is disabled by default. The{fmt}C++ module is not supported. - Set
MAGIC_ENUM_MODULE_IMPORT_STD=ONto enableimport stdsupport. 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
Top Related Projects
Nameof operator for modern C++, simply obtain the name of a variable, type, function, macro, and enum
Convert
designs to code with AI
Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.
Try Visual Copilot