与其他类似的问题不同,这个问题是关于如何使用c++的新特性。

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

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

优雅的方式使用c++ 11、c++ 14或c++ 17的新特性 或者在Boost中使用一些现成的东西 还有一些东西计划在c++ 20中实现

例子

举例往往比冗长的解释更好。 您可以在Coliru上编译和运行这个代码片段。 (另一个前面的例子也可用)

#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) <<'\n';
   std::cout << magic(MyClass::MyEnum::BBB) <<'\n';
   std::cout << magic(MyClass::MyEnum::CCC) <<'\n';
}

约束

请不要无价值的重复其他答案或基本链接。 请避免基于宏的臃肿答案,或尽量减少#define开销。 请不要手动enum ->字符串映射。

很高兴有

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

一个可能的想法是使用c++编译器功能,在编译时使用基于可变参数模板类和constexpr函数的元编程技巧来生成c++代码……


当前回答

根据OP的要求,这里有一个基于Boost preproessor和Variadic Macros的丑陋宏解决方案的精简版本。

它允许类似枚举元素语法的简单列表,并为特定元素设置值,以便

XXX_ENUM(foo,(a,b,(c,42)));

扩大到

enum foo {
    a,
    b,
    c=42
};

与必要的函数一起输出并做一些转换。这个宏已经存在了很长时间,我不完全确定这是最有效的方式,或者它是一种一致的方式,但它一直以来都在工作

完整的代码可以在Ideone和Coliru中看到。

它的巨大丑陋在上面;如果我知道怎么做,我会把它放在剧透后面保护你的眼睛,但markdown不喜欢我。

库(合并在一个头文件中)

#include <boost/preprocessor.hpp>
#include <string>
#include <unordered_map>

namespace xxx
{

template<class T>
struct enum_cast_adl_helper { };

template<class E>
E enum_cast( const std::string& s )
{
    return do_enum_cast(s,enum_cast_adl_helper<E>());
}

template<class E>
E enum_cast( const char* cs )
{
    std::string s(cs);
    return enum_cast<E>(s);
}

} // namespace xxx

#define XXX_PP_ARG_N(                             \
          _1, _2, _3, _4, _5, _6, _7, _8, _9,_10, \
         _11,_12,_13,_14,_15,_16,_17,_18,_19,_20, \
         _21,_22,_23,_24,_25,_26,_27,_28,_29,_30, \
         _31,_32,_33,_34,_35,_36,_37,_38,_39,_40, \
         _41,_42,_43,_44,_45,_46,_47,_48,_49,_50, \
         _51,_52,_53,_54,_55,_56,_57,_58,_59,_60, \
         _61,_62,_63,N,...) N

#define XXX_PP_RSEQ_N()                 \
         63,62,61,60,                   \
         59,58,57,56,55,54,53,52,51,50, \
         49,48,47,46,45,44,43,42,41,40, \
         39,38,37,36,35,34,33,32,31,30, \
         29,28,27,26,25,24,23,22,21,20, \
         19,18,17,16,15,14,13,12,11,10, \
         9,8,7,6,5,4,3,2,1,0 

#define XXX_PP_NARG_(...) XXX_PP_ARG_N(__VA_ARGS__)
#define XXX_PP_NARG(...)  XXX_PP_NARG_(__VA_ARGS__,XXX_PP_RSEQ_N())
#define XXX_TUPLE_SIZE_INTERNAL(TUPLE) XXX_PP_NARG TUPLE

#define XXX_TUPLE_CHOICE(i)                            \
  BOOST_PP_APPLY(                                      \
    BOOST_PP_TUPLE_ELEM(                               \
      25, i, (                                         \
        (0), (1), (2), (3), (4), (5), (6), (7), (8),   \
        (9), (10), (11), (12), (13), (14), (15), (16), \
        (17), (18), (19), (20), (21), (22), (23), (24) \
  ) ) )

#define BOOST_PP_BOOL_00  BOOST_PP_BOOL_0
#define BOOST_PP_BOOL_01  BOOST_PP_BOOL_1
#define BOOST_PP_BOOL_02  BOOST_PP_BOOL_2
#define BOOST_PP_BOOL_03  BOOST_PP_BOOL_3
#define BOOST_PP_BOOL_04  BOOST_PP_BOOL_4
#define BOOST_PP_BOOL_05  BOOST_PP_BOOL_5
#define BOOST_PP_BOOL_06  BOOST_PP_BOOL_6
#define BOOST_PP_BOOL_07  BOOST_PP_BOOL_7
#define BOOST_PP_BOOL_08  BOOST_PP_BOOL_8
#define BOOST_PP_BOOL_09  BOOST_PP_BOOL_9
#define BOOST_PP_BOOL_010 BOOST_PP_BOOL_10
#define BOOST_PP_BOOL_011 BOOST_PP_BOOL_11
#define BOOST_PP_BOOL_012 BOOST_PP_BOOL_12
#define BOOST_PP_BOOL_013 BOOST_PP_BOOL_13
#define BOOST_PP_BOOL_014 BOOST_PP_BOOL_14
#define BOOST_PP_BOOL_015 BOOST_PP_BOOL_15
#define BOOST_PP_BOOL_016 BOOST_PP_BOOL_16
#define BOOST_PP_BOOL_017 BOOST_PP_BOOL_17
#define BOOST_PP_BOOL_018 BOOST_PP_BOOL_18
#define BOOST_PP_BOOL_019 BOOST_PP_BOOL_19
#define BOOST_PP_BOOL_020 BOOST_PP_BOOL_20
#define BOOST_PP_BOOL_021 BOOST_PP_BOOL_21
#define BOOST_PP_BOOL_022 BOOST_PP_BOOL_22
#define BOOST_PP_BOOL_023 BOOST_PP_BOOL_23
#define BOOST_PP_BOOL_024 BOOST_PP_BOOL_24
#define BOOST_PP_BOOL_025 BOOST_PP_BOOL_25
#define BOOST_PP_BOOL_026 BOOST_PP_BOOL_26
#define BOOST_PP_BOOL_027 BOOST_PP_BOOL_27
#define BOOST_PP_BOOL_028 BOOST_PP_BOOL_28
#define BOOST_PP_BOOL_029 BOOST_PP_BOOL_29
#define BOOST_PP_BOOL_030 BOOST_PP_BOOL_30
#define BOOST_PP_BOOL_031 BOOST_PP_BOOL_31
#define BOOST_PP_BOOL_032 BOOST_PP_BOOL_32
#define BOOST_PP_BOOL_033 BOOST_PP_BOOL_33
#define BOOST_PP_BOOL_034 BOOST_PP_BOOL_34
#define BOOST_PP_BOOL_035 BOOST_PP_BOOL_35
#define BOOST_PP_BOOL_036 BOOST_PP_BOOL_36
#define BOOST_PP_BOOL_037 BOOST_PP_BOOL_37
#define BOOST_PP_BOOL_038 BOOST_PP_BOOL_38
#define BOOST_PP_BOOL_039 BOOST_PP_BOOL_39
#define BOOST_PP_BOOL_040 BOOST_PP_BOOL_40
#define BOOST_PP_BOOL_041 BOOST_PP_BOOL_41
#define BOOST_PP_BOOL_042 BOOST_PP_BOOL_42
#define BOOST_PP_BOOL_043 BOOST_PP_BOOL_43
#define BOOST_PP_BOOL_044 BOOST_PP_BOOL_44
#define BOOST_PP_BOOL_045 BOOST_PP_BOOL_45
#define BOOST_PP_BOOL_046 BOOST_PP_BOOL_46
#define BOOST_PP_BOOL_047 BOOST_PP_BOOL_47
#define BOOST_PP_BOOL_048 BOOST_PP_BOOL_48
#define BOOST_PP_BOOL_049 BOOST_PP_BOOL_49
#define BOOST_PP_BOOL_050 BOOST_PP_BOOL_50
#define BOOST_PP_BOOL_051 BOOST_PP_BOOL_51
#define BOOST_PP_BOOL_052 BOOST_PP_BOOL_52
#define BOOST_PP_BOOL_053 BOOST_PP_BOOL_53
#define BOOST_PP_BOOL_054 BOOST_PP_BOOL_54
#define BOOST_PP_BOOL_055 BOOST_PP_BOOL_55
#define BOOST_PP_BOOL_056 BOOST_PP_BOOL_56
#define BOOST_PP_BOOL_057 BOOST_PP_BOOL_57
#define BOOST_PP_BOOL_058 BOOST_PP_BOOL_58
#define BOOST_PP_BOOL_059 BOOST_PP_BOOL_59
#define BOOST_PP_BOOL_060 BOOST_PP_BOOL_60
#define BOOST_PP_BOOL_061 BOOST_PP_BOOL_61
#define BOOST_PP_BOOL_062 BOOST_PP_BOOL_62
#define BOOST_PP_BOOL_063 BOOST_PP_BOOL_63

#define BOOST_PP_DEC_00  BOOST_PP_DEC_0
#define BOOST_PP_DEC_01  BOOST_PP_DEC_1
#define BOOST_PP_DEC_02  BOOST_PP_DEC_2
#define BOOST_PP_DEC_03  BOOST_PP_DEC_3
#define BOOST_PP_DEC_04  BOOST_PP_DEC_4
#define BOOST_PP_DEC_05  BOOST_PP_DEC_5
#define BOOST_PP_DEC_06  BOOST_PP_DEC_6
#define BOOST_PP_DEC_07  BOOST_PP_DEC_7
#define BOOST_PP_DEC_08  BOOST_PP_DEC_8
#define BOOST_PP_DEC_09  BOOST_PP_DEC_9
#define BOOST_PP_DEC_010 BOOST_PP_DEC_10
#define BOOST_PP_DEC_011 BOOST_PP_DEC_11
#define BOOST_PP_DEC_012 BOOST_PP_DEC_12
#define BOOST_PP_DEC_013 BOOST_PP_DEC_13
#define BOOST_PP_DEC_014 BOOST_PP_DEC_14
#define BOOST_PP_DEC_015 BOOST_PP_DEC_15
#define BOOST_PP_DEC_016 BOOST_PP_DEC_16
#define BOOST_PP_DEC_017 BOOST_PP_DEC_17
#define BOOST_PP_DEC_018 BOOST_PP_DEC_18
#define BOOST_PP_DEC_019 BOOST_PP_DEC_19
#define BOOST_PP_DEC_020 BOOST_PP_DEC_20
#define BOOST_PP_DEC_021 BOOST_PP_DEC_21
#define BOOST_PP_DEC_022 BOOST_PP_DEC_22
#define BOOST_PP_DEC_023 BOOST_PP_DEC_23
#define BOOST_PP_DEC_024 BOOST_PP_DEC_24
#define BOOST_PP_DEC_025 BOOST_PP_DEC_25
#define BOOST_PP_DEC_026 BOOST_PP_DEC_26
#define BOOST_PP_DEC_027 BOOST_PP_DEC_27
#define BOOST_PP_DEC_028 BOOST_PP_DEC_28
#define BOOST_PP_DEC_029 BOOST_PP_DEC_29
#define BOOST_PP_DEC_030 BOOST_PP_DEC_30
#define BOOST_PP_DEC_031 BOOST_PP_DEC_31
#define BOOST_PP_DEC_032 BOOST_PP_DEC_32
#define BOOST_PP_DEC_033 BOOST_PP_DEC_33
#define BOOST_PP_DEC_034 BOOST_PP_DEC_34
#define BOOST_PP_DEC_035 BOOST_PP_DEC_35
#define BOOST_PP_DEC_036 BOOST_PP_DEC_36
#define BOOST_PP_DEC_037 BOOST_PP_DEC_37
#define BOOST_PP_DEC_038 BOOST_PP_DEC_38
#define BOOST_PP_DEC_039 BOOST_PP_DEC_39
#define BOOST_PP_DEC_040 BOOST_PP_DEC_40
#define BOOST_PP_DEC_041 BOOST_PP_DEC_41
#define BOOST_PP_DEC_042 BOOST_PP_DEC_42
#define BOOST_PP_DEC_043 BOOST_PP_DEC_43
#define BOOST_PP_DEC_044 BOOST_PP_DEC_44
#define BOOST_PP_DEC_045 BOOST_PP_DEC_45
#define BOOST_PP_DEC_046 BOOST_PP_DEC_46
#define BOOST_PP_DEC_047 BOOST_PP_DEC_47
#define BOOST_PP_DEC_048 BOOST_PP_DEC_48
#define BOOST_PP_DEC_049 BOOST_PP_DEC_49
#define BOOST_PP_DEC_050 BOOST_PP_DEC_50
#define BOOST_PP_DEC_051 BOOST_PP_DEC_51
#define BOOST_PP_DEC_052 BOOST_PP_DEC_52
#define BOOST_PP_DEC_053 BOOST_PP_DEC_53
#define BOOST_PP_DEC_054 BOOST_PP_DEC_54
#define BOOST_PP_DEC_055 BOOST_PP_DEC_55
#define BOOST_PP_DEC_056 BOOST_PP_DEC_56
#define BOOST_PP_DEC_057 BOOST_PP_DEC_57
#define BOOST_PP_DEC_058 BOOST_PP_DEC_58
#define BOOST_PP_DEC_059 BOOST_PP_DEC_59
#define BOOST_PP_DEC_060 BOOST_PP_DEC_60
#define BOOST_PP_DEC_061 BOOST_PP_DEC_61
#define BOOST_PP_DEC_062 BOOST_PP_DEC_62
#define BOOST_PP_DEC_063 BOOST_PP_DEC_63

#define XXX_TO_NUMx(x) 0 ## x
#define XXX_TO_NUM(x) BOOST_PP_ADD(0,XXX_TO_NUMx(x))
#define XXX_STRINGIZEX(x) # x
#define XXX_VSTRINGIZE_SINGLE(a,b,x) XXX_STRINGIZE(x)
#define XXX_VSTRINGIZE_TUPLE(tpl) XXX_TUPLE_FOR_EACH(XXX_VSTRINGIZE_SINGLE,,tpl)
#define XXX_TUPLE_SIZE(TUPLE) XXX_TO_NUM(XXX_TUPLE_CHOICE(XXX_TUPLE_SIZE_INTERNAL(TUPLE)))
#define XXX_TUPLE_FOR_EACH(MACRO,DATA,TUPLE) BOOST_PP_LIST_FOR_EACH(MACRO,DATA,BOOST_PP_TUPLE_TO_LIST(XXX_TUPLE_SIZE(TUPLE),TUPLE))
#define XXX_STRINGIZE(x) XXX_STRINGIZEX(x)
#define XXX_VSTRINGIZE(...) XXX_VSTRINGIZE_TUPLE((__VA_ARGS__))
#define XXX_CAST_TO_VOID_ELEMENT(r,data,elem) (void)(elem);
#define XXX_CAST_TO_VOID_INTERNAL(TUPLE) XXX_TUPLE_FOR_EACH(XXX_CAST_TO_VOID_ELEMENT,,TUPLE)    
#define XXX_CAST_TO_VOID(...) XXX_CAST_TO_VOID_INTERNAL((__VA_ARGS__))
#define XXX_ENUM_EXTRACT_SP(en) BOOST_PP_TUPLE_ELEM(XXX_TUPLE_SIZE(en),0,en) = BOOST_PP_TUPLE_ELEM(XXX_TUPLE_SIZE(en),1,en)
#define XXX_ENUM_ELEMENT(r,data,elem) BOOST_PP_IF( XXX_TUPLE_SIZE(elem), XXX_ENUM_EXTRACT_SP(elem), elem) ,
#define XXX_ENUM_EXTRACT_ELEMENT(en) BOOST_PP_TUPLE_ELEM(XXX_TUPLE_SIZE(en),0,en)
#define XXX_ENUM_CASE_ELEMENT(en) BOOST_PP_IF( XXX_TUPLE_SIZE(en), XXX_ENUM_EXTRACT_ELEMENT(en), en )
#define XXX_ENUM_CASE(r,data,elem) case data :: XXX_ENUM_CASE_ELEMENT(elem) : return #data "::" XXX_STRINGIZE(XXX_ENUM_CASE_ELEMENT(elem));
#define XXX_ENUM_IFELSE(r,data,elem) else if( en == data :: XXX_ENUM_CASE_ELEMENT(elem)) { return #data "::" XXX_STRINGIZE(XXX_ENUM_CASE_ELEMENT(elem)); }
#define XXX_ENUM_CASTLIST(r,data,elem) { XXX_STRINGIZE(XXX_ENUM_CASE_ELEMENT(elem)), data :: XXX_ENUM_CASE_ELEMENT(elem) },
#define XXX_ENUM_QUALIFIED_CASTLIST(r,data,elem) { #data "::" XXX_STRINGIZE(XXX_ENUM_CASE_ELEMENT(elem)), data :: XXX_ENUM_CASE_ELEMENT(elem) },

#define XXX_ENUM_INTERNAL(TYPE,NAME,TUPLE)                       \
enum TYPE                                                        \
{                                                                \
   XXX_TUPLE_FOR_EACH(XXX_ENUM_ELEMENT,,TUPLE)                   \
   BOOST_PP_CAT(last_enum_,NAME)                                 \
};                                                               \
                                                                 \
inline                                                           \
const char* to_string( NAME en )                                 \
{                                                                \
   if(false)                                                     \
   {                                                             \
   }                                                             \
   XXX_TUPLE_FOR_EACH(XXX_ENUM_IFELSE,NAME,TUPLE)                \
   else if( en == NAME :: BOOST_PP_CAT(last_enum_,NAME) )        \
   {                                                             \
     return XXX_VSTRINGIZE(NAME,::,BOOST_PP_CAT(last_enum_,NAME));  \
   }                                                             \
   else                                                          \
   {                                                             \
     return "Invalid enum value specified for " # NAME;          \
   }                                                             \
}                                                                \
                                                                 \
inline                                                           \
std::ostream& operator<<( std::ostream& os, const NAME& en )     \
{                                                                \
   os << to_string(en);                                          \
   return os;                                                    \
}                                                                \
                                                                 \
inline                                                           \
NAME do_enum_cast( const std::string& s, const ::xxx::enum_cast_adl_helper<NAME>& ) \
{                                                                \
  static const std::unordered_map<std::string,NAME> map =        \
  {                                                              \
    XXX_TUPLE_FOR_EACH(XXX_ENUM_CASTLIST,NAME,TUPLE)             \
    XXX_TUPLE_FOR_EACH(XXX_ENUM_QUALIFIED_CASTLIST,NAME,TUPLE)   \
  };                                                             \
                                                                 \
  auto cit = map.find(s);                                        \
  if( cit == map.end() )                                         \
  {                                                              \
    throw std::runtime_error("Invalid value to cast to enum");   \
  }                                                              \
  return cit->second;                                            \
}

#define XXX_ENUM(NAME,TUPLE) XXX_ENUM_INTERNAL(NAME,NAME,TUPLE)
#define XXX_ENUM_CLASS(NAME,TUPLE) XXX_ENUM_INTERNAL(class NAME,NAME,TUPLE)
#define XXX_ENUM_CLASS_TYPE(NAME,TYPE,TUPLE) XXX_ENUM_INTERNAL(class NAME : TYPE,NAME,TUPLE)
#define XXX_ENUM_TYPE(NAME,TYPE,TUPLE) XXX_ENUM_INTERNAL(NAME : TYPE,NAME,TUPLE)

使用

#include "xxx_enum.h"  // the above lib
#include <iostream>

XXX_ENUM(foo,(a,b,(c,42)));

int main()
{
  std::cout << "foo::a = "            << foo::a            <<'\n';
  std::cout << "(int)foo::c = "       << (int)foo::c       <<'\n';
  std::cout << "to_string(foo::b) = " << to_string(foo::b) <<'\n';
  std::cout << "xxx::enum_cast<foo>(\"b\") = " << xxx::enum_cast<foo>("b") <<'\n';
}

编译(在main.cpp中复制粘贴头文件)

> g++ --version | sed 1q
g++ (GCC) 4.9.2

> g++ -std=c++14 -pedantic -Wall -Wextra main.cpp
main.cpp:268:31: warning: extra ';' [-Wpedantic]
     XXX_ENUM(foo,(a,b,(c,42)));
                               ^

输出

foo::a = foo::a
(int)foo::c = 42
to_string(foo::b) = foo::b
xxx::enum_cast<foo>("b") = foo::b

其他回答

我的解决方案,使用预处理器定义。

您可以在https://repl.it/@JomaCorpFX/nameof#main.cpp上查看此代码

#include <iostream>
#include <stdexcept>
#include <regex>

typedef std::string String;
using namespace std::literals::string_literals;

class Strings
{
public:
    static String TrimStart(const std::string& data)
    {
        String s = data;
        s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](unsigned char ch) {
            return !std::isspace(ch);
        }));
        return s;
    }

    static String TrimEnd(const std::string& data)
    {
        String s = data;
        s.erase(std::find_if(s.rbegin(), s.rend(), [](unsigned char ch) {
            return !std::isspace(ch);
        }).base(),
            s.end());
        return s;
    }

    static String Trim(const std::string& data)
    {
        return TrimEnd(TrimStart(data));
    }

    static String Replace(const String& data, const String& toFind, const String& toReplace)
    {
        String result = data;
        size_t pos = 0;
        while ((pos = result.find(toFind, pos)) != String::npos)
        {
            result.replace(pos, toFind.length(), toReplace);
            pos += toReplace.length();
            pos = result.find(toFind, pos);
        }
        return result;
    }

};

static String Nameof(const String& name)
{
    std::smatch groups;
    String str = Strings::Trim(name);
    if (std::regex_match(str, groups, std::regex(u8R"(^&?([_a-zA-Z]\w*(->|\.|::))*([_a-zA-Z]\w*)$)")))
    {
        if (groups.size() == 4)
        {
            return groups[3];
        }
    }
    throw std::invalid_argument(Strings::Replace(u8R"(nameof(#). Invalid identifier "#".)", u8"#", name));
}

#define nameof(name) Nameof(u8## #name ## s)
#define cnameof(name) Nameof(u8## #name ## s).c_str()

enum TokenType {
    COMMA,
    PERIOD,
    Q_MARK
};

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

int main() {
    String greetings = u8"Hello"s;
    std::cout << nameof(COMMA) << std::endl;
    std::cout << nameof(TokenType::PERIOD) << std::endl;
    std::cout << nameof(TokenType::Q_MARK) << std::endl;
    std::cout << nameof(int) << std::endl;
    std::cout << nameof(std::string) << std::endl;
    std::cout << nameof(Strings) << std::endl;
    std::cout << nameof(String) << std::endl;
    std::cout << nameof(greetings) << std::endl;
    std::cout << nameof(&greetings) << std::endl;
    std::cout << nameof(greetings.c_str) << std::endl;
    std::cout << nameof(std::string::npos) << std::endl;
    std::cout << nameof(MyClass::MyEnum::AAA) << std::endl;
    std::cout << nameof(MyClass::MyEnum::BBB) << std::endl;
    std::cout << nameof(MyClass::MyEnum::CCC) << std::endl;


    std::cin.get();
    return 0;
}

输出

COMMA
PERIOD
Q_MARK
int
string
Strings
String
greetings
greetings
c_str
npos
AAA
BBB
CCC

视觉C + +。

对于c++ 17 c++ 20,您将对反思研究小组(SG7)的工作感兴趣。还有一系列平行的论文,包括措辞(P0194)和基本原理、设计和进化(P0385)。(链接解析为每个系列的最新论文。)

从P0194r2(2016-10-15)开始,该语法将使用建议的reflexpr关键字:

meta::get_base_name_v<
  meta::get_element_m<
    meta::get_enumerators_m<reflexpr(MyEnum)>,
    0>
  >

例如(改编自Matus Choclik的reflexpr clang分支):

#include <reflexpr>
#include <iostream>

enum MyEnum { AAA = 1, BBB, CCC = 99 };

int main()
{
  auto name_of_MyEnum_0 = 
    std::meta::get_base_name_v<
      std::meta::get_element_m<
        std::meta::get_enumerators_m<reflexpr(MyEnum)>,
        0>
    >;

  // prints "AAA"
  std::cout << name_of_MyEnum_0 << std::endl;
}

静态反射未能进入c++ 17(更确切地说,进入了2016年11月在Issaquah举行的标准会议上提出的可能是最终草案),但有信心它将进入c++ 20;摘自赫布·萨特的旅行报告:

特别是,反射研究小组审查了最新合并的静态反射提案,并发现它准备在我们的下一次会议上进入主要的进化小组,开始考虑TS或下一个标准的统一静态反射提案。

下面的解决方案是基于给定enum的std::array<std::string,N>。

对于将enum转换为std::string,我们只需将enum转换为size_t,然后从数组中查找字符串。该操作是O(1),不需要堆分配。

#include <boost/preprocessor/seq/transform.hpp>
#include <boost/preprocessor/seq/enum.hpp>
#include <boost/preprocessor/stringize.hpp>

#include <string>
#include <array>
#include <iostream>

#define STRINGIZE(s, data, elem) BOOST_PP_STRINGIZE(elem)

// ENUM
// ============================================================================
#define ENUM(X, SEQ) \
struct X {   \
    enum Enum {BOOST_PP_SEQ_ENUM(SEQ)}; \
    static const std::array<std::string,BOOST_PP_SEQ_SIZE(SEQ)> array_of_strings() { \
        return {{BOOST_PP_SEQ_ENUM(BOOST_PP_SEQ_TRANSFORM(STRINGIZE, 0, SEQ))}}; \
    } \
    static std::string to_string(Enum e) { \
        auto a = array_of_strings(); \
        return a[static_cast<size_t>(e)]; \
    } \
}

对于std::string到enum的转换,我们必须对数组进行线性搜索,并将数组索引强制转换为enum。

这里有一些用法示例:http://coliru.stacked-crooked.com/a/e4212f93bee65076

编辑:重做我的解决方案,以便自定义Enum可以在类中使用。

我不确定这种方法是否已经包含在其他答案中(实际上是,见下文)。我遇到过这个问题很多次,但没有找到不使用混淆宏或第三方库的解决方案。因此,我决定编写自己的模糊宏版本。

我想启用的是等价的

enum class test1 { ONE, TWO = 13, SIX };

std::string toString(const test1& e) { ... }

int main() {
    test1 x;
    std::cout << toString(x) << "\n";
    std::cout << toString(test1::TWO) << "\n";
    std::cout << static_cast<std::underlying_type<test1>::type>(test1::TWO) << "\n";
    //std::cout << toString(123);// invalid
}

应该打印

ONE
TWO
13

我不是宏的粉丝。然而,除非c++本身支持将枚举转换为字符串,否则必须使用某种代码生成和/或宏(我怀疑这种情况不会很快发生)。我正在使用x宏:

// x_enum.h
#include <string>
#include <map>
#include <type_traits>
#define x_begin enum class x_name {
#define x_val(X) X
#define x_value(X,Y) X = Y
#define x_end };
x_enum_def
#undef x_begin
#undef x_val
#undef x_value
#undef x_end

#define x_begin inline std::string toString(const x_name& e) { \
                static std::map<x_name,std::string> names = { 
#define x_val(X)      { x_name::X , #X }
#define x_value(X,Y)  { x_name::X , #X }
#define x_end }; return names[e]; }
x_enum_def
#undef x_begin
#undef x_val
#undef x_value
#undef x_end
#undef x_name
#undef x_enum_def

其中大部分是定义和取消定义符号,用户将通过include将这些符号作为参数传递给X-marco。用法是这样的

#define x_name test1
#define x_enum_def x_begin x_val(ONE) , \
                           x_value(TWO,13) , \
                           x_val(SIX) \
                   x_end
#include "x_enum.h"

现场演示

注意,我还没有包括选择基础类型。到目前为止,我还不需要它,但它应该是直接修改代码来启用它。

写完这篇文章后,我才意识到这和eferion的答案很相似。也许我以前读过,也许它是灵感的主要来源。我总是不能理解x -宏,直到我写了自己的;)。

您可以使用select()函数,这实际上只是一个简短的开关;这不是真正意义上的解决方案,但它让生活更容易:

enum
{
  NORMAL,
  INVALID
} state(NORMAL);

//std::cout << (state ? "INVALID" : "NORMAL") << std::endl;
std::cout << select(state, "NORMAL", "INVALID") << std::endl;

select()函数在SIMD/GPU编程中很常见。它们是三元?:运算符的推广。还可以将select()视为函数数组(实现数组数据结构的函数)。

这里有一个完整的例子。