在现代 C++11/C++14/C++17 和未来的 C++20 中枚举到字符串

2021-12-05 00:00:00 string c enums c++ c++20 c++17

与所有其他类似问题相反,这个问题是关于使用新的 C++ 特性.

  • 2008 c 有没有一种简单的方法可以将 C++ 枚举转换为字符串?
  • 2008 c 在 C 中使用枚举类型的变量作为字符串的简单方法?
  • 2008 c++ 如何轻松地将 C++ 枚举映射到字符串
  • 2008 c++ 使某些东西既是 C 标识符又是字符串?
  • 2008 c++ 是否有将 C++ 枚举转换为字符串的简单脚本?
  • 2009 c++ 如何在 C++ 中使用枚举作为标志?
  • 2011 c++ 如何将枚举类型变量转换为字符串?
  • 2011 c++ 枚举到字符串 C++
  • 2011 c++ 如何将枚举类型变量转换为字符串?
  • 2012 c 如何在 c 中将枚举名称转换为字符串
  • 2013 c 在 C 中对条件编译的枚举进行字符串化

看了很多答案,我还没有找到:

  • 使用 C++11 的优雅方式,C++14 或 C++17 新功能
  • 或者在 Boost
  • 中准备使用的东西
  • 其他为 C++20
  • 的计划

示例

一个例子往往比一个长的解释要好.
您可以在 Coliru 上编译并运行此代码段.
(另一个前面的例子也是可用的)

#include #include 结构体{枚举类 MyEnum : char {AAA = -8,BBB = '8',CCC = AAA + BBB};};//用一些更快的编译时生成的代码替换magic()//(你可以用 std::string 替换返回类型//如果这对你来说更容易)const char* 魔法 (MyClass::MyEnum e){const std::map我的枚举字符串{{ MyClass::MyEnum::AAA, "MyClass::MyEnum::AAA";},{ MyClass::MyEnum::BBB, "MyClass::MyEnum::BBB";},{ MyClass::MyEnum::CCC, "MyClass::MyEnum::CCC";}};auto it = MyEnumStrings.find(e);返回它 == MyEnumStrings.end() ?超出范围":它->第二;}int main(){std::cout <<魔术(MyClass::MyEnum::AAA)<<'
';std::cout <<魔术(MyClass::MyEnum::BBB)<<'
';std::cout <<魔术(MyClass::MyEnum::CCC)<<'
';}

限制条件

  • 请不要重复其他答案或基本链接.莉>
  • 请避免基于宏的臃肿答案,或尽量减少 #define 开销.
  • 请不要手动enum ->string 映射.

很高兴有

  • 支持 enum 值从非零的数字开始
  • 支持负enum
  • 支持碎片化的enum
  • 支持类枚举 (C++11)
  • 支持 class enum : 具有任何允许的 (C++11)
  • 编译时(非运行时)转换为字符串,
    或者至少在运行时快速执行(例如 std::map 不是一个好主意......)
  • constexpr(C++11,然后在 C++14/17/20 中放松)
  • noexcept (C++11)
  • C++17/C++20 友好代码段

一个可能的想法是使用 C++ 编译器功能在编译时使用基于 variadic template classconstexpr 函数的元编程技巧生成 C++ 代码..

解决方案

Magic Enum 仅标头库为 C++17 的枚举(到字符串、从字符串、迭代)提供静态反射.

#include 枚举颜色 { 红色 = 2, 蓝色 = 4, 绿色 = 8 };颜色颜色 = 颜色::红色;auto color_name = magic_enum::enum_name(color);//颜色名称 ->红色的"std::string color_name{"GREEN"};自动颜色 = magic_enum::enum_cast(color_name)如果(颜色.has_value()){//color.value() ->颜色::绿色};

有关更多示例,请查看主存储库 https://github.com/Neargye/magic_enum.>

缺点在哪里?

此库使用特定于编译器的 hack(基于 __PRETTY_FUNCTION__/__FUNCSIG__),适用于 Clang >= 5、MSVC >= 15.3 和 GCC >= 9.

枚举值必须在 [MAGIC_ENUM_RANGE_MIN, MAGIC_ENUM_RANGE_MAX] 范围内.

  • 默认MAGIC_ENUM_RANGE_MIN = -128MAGIC_ENUM_RANGE_MAX = 128.

  • 如果所有枚举类型默认需要另一个范围,重新定义宏MAGIC_ENUM_RANGE_MINMAGIC_ENUM_RANGE_MAX.

  • MAGIC_ENUM_RANGE_MIN 必须小于或等于 0,并且必须大于 INT16_MIN.

  • MAGIC_ENUM_RANGE_MAX 必须大于 0 且必须小于 INT16_MAX.

  • 如果需要特定枚举类型的另一个范围,请为必要的枚举类型添加特殊化 enum_range.

    #include 枚举数 { 一 = 100, 二 = 200, 三 = 300 };命名空间magic_enum {模板 <>struct enum_range{静态 constexpr int min = 100;静态 constexpr int 最大值 = 300;};}

Contrary to all other similar questions, this question is about using the new C++ features.

  • 2008 c Is there a simple way to convert C++ enum to string?
  • 2008 c Easy way to use variables of enum types as string in C?
  • 2008 c++ How to easily map c++ enums to strings
  • 2008 c++ Making something both a C identifier and a string?
  • 2008 c++ Is there a simple script to convert C++ enum to string?
  • 2009 c++ How to use enums as flags in C++?
  • 2011 c++ How to convert an enum type variable to a string?
  • 2011 c++ Enum to String C++
  • 2011 c++ How to convert an enum type variable to a string?
  • 2012 c How to convert enum names to string in c
  • 2013 c Stringifying an conditionally compiled enum in C

After reading many answers, I did not yet find any:

  • Elegant way using C++11, C++14 or C++17 new features
  • Or something ready-to-use in Boost
  • Else something planned for C++20

Example

An example is often better than a long explanation.
You can compile and run this snippet on Coliru.
(Another former example is also available)

#include <map>
#include <iostream>

struct MyClass
{
    enum class MyEnum : char {
        AAA = -8,
        BBB = '8',
        CCC = AAA + BBB
    };
};

// Replace magic() by some faster compile-time generated code
// (you're allowed to replace the return type with std::string
// if that's easier for you)
const char* magic (MyClass::MyEnum e)
{
    const std::map<MyClass::MyEnum,const char*> MyEnumStrings {
        { MyClass::MyEnum::AAA, "MyClass::MyEnum::AAA" },
        { MyClass::MyEnum::BBB, "MyClass::MyEnum::BBB" },
        { MyClass::MyEnum::CCC, "MyClass::MyEnum::CCC" }
    };
    auto   it  = MyEnumStrings.find(e);
    return it == MyEnumStrings.end() ? "Out of range" : it->second;
}

int main()
{
   std::cout << magic(MyClass::MyEnum::AAA) <<'
';
   std::cout << magic(MyClass::MyEnum::BBB) <<'
';
   std::cout << magic(MyClass::MyEnum::CCC) <<'
';
}

Constraints

  • Please no valueless duplication of other answers or basic link.
  • Please avoid bloat macro-based answer, or try to reduce the #define overhead as minimum as possible.
  • Please no manual enum -> string mapping.

Nice to have

  • Support enum values starting from a number different from zero
  • Support negative enum values
  • Support fragmented enum values
  • Support class enum (C++11)
  • Support class enum : <type> having any allowed <type> (C++11)
  • Compile-time (not run-time) conversions to a string,
    or at least fast execution at run-time (e.g. std::map is not a great idea...)
  • constexpr (C++11, then relaxed in C++14/17/20)
  • noexcept (C++11)
  • C++17/C++20 friendly snippet

One possible idea could be using the C++ compiler capabilities to generate C++ code at compilation-time using meta-programming tricks based on variadic template class and constexpr functions...

解决方案

Magic Enum header-only library provides static reflection for enums (to string, from string, iteration) for C++17.

#include <magic_enum.hpp>

enum Color { RED = 2, BLUE = 4, GREEN = 8 };

Color color = Color::RED;
auto color_name = magic_enum::enum_name(color);
// color_name -> "RED"

std::string color_name{"GREEN"};
auto color = magic_enum::enum_cast<Color>(color_name)
if (color.has_value()) {
  // color.value() -> Color::GREEN
};

For more examples check home repository https://github.com/Neargye/magic_enum.

Where is the drawback?

This library uses a compiler-specific hack (based on __PRETTY_FUNCTION__ / __FUNCSIG__), which works on Clang >= 5, MSVC >= 15.3 and GCC >= 9.

Enum value must be in range [MAGIC_ENUM_RANGE_MIN, MAGIC_ENUM_RANGE_MAX].

  • By default MAGIC_ENUM_RANGE_MIN = -128, MAGIC_ENUM_RANGE_MAX = 128.

  • If need another range for all enum types by default, redefine the macro MAGIC_ENUM_RANGE_MIN and MAGIC_ENUM_RANGE_MAX.

  • MAGIC_ENUM_RANGE_MIN must be less or equals than 0 and must be greater than INT16_MIN.

  • MAGIC_ENUM_RANGE_MAX must be greater than 0 and must be less than INT16_MAX.

  • If need another range for specific enum type, add specialization enum_range for necessary enum type.

    #include <magic_enum.hpp>
    
    enum number { one = 100, two = 200, three = 300 };
    
    namespace magic_enum {
    template <>
      struct enum_range<number> {
        static constexpr int min = 100;
        static constexpr int max = 300;
    };
    }
    

相关文章