Easy way to use variables of enum types as string in C?
我想做的是:
1 | typedef enum { ONE, TWO, THREE } Numbers; |
我正在尝试编写一个函数,它将执行类似于以下内容的切换案例:
1 2 3 4 5 6 7 8 9 10 11 12 13 | char num_str[10]; int process_numbers_str(Numbers num) { switch(num) { case ONE: case TWO: case THREE: { strcpy(num_str, num); //some way to get the symbolic constant name in here? } break; default: return 0; //no match return 1; } |
不是在每种情况下都定义,有没有一种方法可以像我在上面所做的那样使用枚举变量来设置它?
同时生成C标识符和字符串的技术?可以在这里使用。
与通常的预处理器一样,编写和理解预处理器部分可能很困难,包括将宏传递给其他宏,并涉及使用和运算符,但使用它确实很容易。我发现这种样式对于长枚举非常有用,在长枚举中维护同一列表两次确实很麻烦。
工厂代码-仅键入一次,通常隐藏在标题中:枚举:h:
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 | // expansion macro for enum value definition #define ENUM_VALUE(name,assign) name assign, // expansion macro for enum to string conversion #define ENUM_CASE(name,assign) case name: return #name; // expansion macro for string to enum conversion #define ENUM_STRCMP(name,assign) if (!strcmp(str,#name)) return name; /// declare the access function and define enum values #define DECLARE_ENUM(EnumType,ENUM_DEF) \ enum EnumType { \ ENUM_DEF(ENUM_VALUE) \ }; \ const char *GetString(EnumType dummy); \ EnumType Get##EnumType##Value(const char *string); \ /// define the access function names #define DEFINE_ENUM(EnumType,ENUM_DEF) \ const char *GetString(EnumType value) \ { \ switch(value) \ { \ ENUM_DEF(ENUM_CASE) \ default: return""; /* handle input error */ \ } \ } \ EnumType Get##EnumType##Value(const char *str) \ { \ ENUM_DEF(ENUM_STRCMP) \ return (EnumType)0; /* handle input error */ \ } \ |
工厂使用
H:
1 2 3 4 5 6 7 8 | #include"enumFactory.h" #define SOME_ENUM(XX) \ XX(FirstValue,) \ XX(SecondValue,) \ XX(SomeOtherValue,=50) \ XX(OneMoreValue,=100) \ DECLARE_ENUM(SomeEnum,SOME_ENUM) |
CPP:
1 2 | #include"someEnum.h" DEFINE_ENUM(SomeEnum,SOME_ENUM) |
这项技术可以很容易地扩展,以便xx宏接受更多的参数,您还可以准备更多的宏来代替xx以满足不同的需要,类似于我在这个示例中提供的三个。
使用include/define/undef与X宏进行比较虽然这类似于其他人提到的X宏,但我认为这个解决方案更优雅,因为它不需要取消任何东西的标记,这允许您隐藏更多复杂的东西在工厂中头文件-头文件是您在需要定义新枚举时根本不接触的东西,因此新枚举澄清要短得多,而且要干净得多。
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 | // Define your enumeration like this (in say numbers.h); ENUM_BEGIN( Numbers ) ENUM(ONE), ENUM(TWO), ENUM(FOUR) ENUM_END( Numbers ) // The macros are defined in a more fundamental .h file (say defs.h); #define ENUM_BEGIN(typ) enum typ { #define ENUM(nam) nam #define ENUM_END(typ) }; // Now in one and only one .c file, redefine the ENUM macros and reinclude // the numbers.h file to build a string table #undef ENUM_BEGIN #undef ENUM #undef ENUM_END #define ENUM_BEGIN(typ) const char * typ ## _name_table [] = { #define ENUM(nam) #nam #define ENUM_END(typ) }; #undef NUMBERS_H_INCLUDED // whatever you need to do to enable reinclusion #include"numbers.h" // Now you can do exactly what you want to do, with no retyping, and for any // number of enumerated types defined with the ENUM macro family // Your code follows; char num_str[10]; int process_numbers_str(Numbers num) { switch(num) { case ONE: case TWO: case THREE: { strcpy(num_str, Numbers_name_table[num]); // eg TWO ->"TWO" } break; default: return 0; //no match return 1; } // Sweet no ? After being frustrated by this for years, I finally came up // with this solution for my most recent project and plan to reuse the idea // forever |
确实有一种方法可以做到这一点——使用x()宏。这些宏使用C预处理器从源数据列表中构造枚举、数组和代码块。您只需要向包含x()宏的定义中添加新项。switch语句将自动展开。
您的示例可以写如下:
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 | // Source data -- Enum, String #define X_NUMBERS \ X(ONE, "one") \ X(TWO, "two") \ X(THREE,"three") ... // Use preprocessor to create the Enum typedef enum { #define X(Enum, String) Enum, X_NUMBERS #undef X } Numbers; ... // Use Preprocessor to expand data into switch statement cases switch(num) { #define X(Enum, String) \ case Enum: strcpy(num_str, String); break; X_NUMBERS #undef X default: return 0; break; } return 1; |
有更有效的方法(即使用x宏创建字符串数组和枚举索引),但这是最简单的演示。
没有内置的解决方案。最简单的方法是使用
我知道你有几个很可靠的答案,但是你知道C预处理器中的运算符吗?
它允许您这样做:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | #define MACROSTR(k) #k typedef enum { kZero, kOne, kTwo, kThree } kConst; static char *kConstStr[] = { MACROSTR(kZero), MACROSTR(kOne), MACROSTR(kTwo), MACROSTR(kThree) }; static void kConstPrinter(kConst k) { printf("%s", kConstStr[k]); } |
的吻。你会做所有的sorts之其他开关/案例的事情与你的enums所以为什么要印刷在不同的吗?forgetting的情况下在你的打印routine是不是问题的huge新政",当你认为有意义的地方,你可以忘记其他100的案例。只是compile墙,将警告美国非exhaustive matches案例。不要用"违约",因为这将使开关exhaustive和你得到warnings韩元。代替,把开关和退出交易与违约的情况下,像这样… P / < >
1 2 3 4 5 6 7 8 | const char *myenum_str(myenum e) { switch(e) { case ONE: return"one"; case TWO: return"two"; } return"invalid"; } |
C或C++不提供这个功能,虽然我经常需要它。
下面的代码可以工作,尽管它最适合非稀疏枚举。
1 2 3 4 | typedef enum { ONE, TWO, THREE } Numbers; char *strNumbers[] = {"one","two","three"}; printf ("Value for TWO is %s ",strNumbers[TWO]); |
我指的是不稀疏的形状
1 | typedef enum { ONE, FOUR_THOUSAND = 4000 } Numbers; |
因为这其中有巨大的差距。
这个方法的优点是,它将枚举和字符串的定义放在一起;在函数中有一个switch语句可以将它们放在一起。这意味着你不太可能改变其中一个。
*使用的提升:尽可能让一个解决方案:preprocessor elegant喜欢以下: P / < >
步骤1:包括同步头文件: P / < >
1 | #include"EnumUtilities.h" |
步骤2:enumeration声明的对象与以下语法: P / < >
1 2 3 4 5 | MakeEnum( TestData, (x) (y) (z) ); |
步骤3:使用你的数据: P / < >
得到一些的元素: P / < >
1 | td::cout <<"Number of Elements:" << TestDataCount << std::endl; |
得到的字符串:"美联社 P / < >
1 2 3 | std::cout <<"Value of" << TestData2String(x) <<" is" << x << std::endl; std::cout <<"Value of" << TestData2String(y) <<" is" << y << std::endl; std::cout <<"Value of" << TestData2String(z) <<" is" << z << std::endl; |
我每天早晨的enum值从字符串:美联社 P / < >
1 2 3 | std::cout <<"Value of x is" << TestData2Enum("x") << std::endl; std::cout <<"Value of y is" << TestData2Enum("y") << std::endl; std::cout <<"Value of z is" << TestData2Enum("z") << std::endl; |
这看起来干净和紧凑,与没有额外的文件包括。 "code)写在enumutilities.h的以下: P / < >
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 | #include <boost/preprocessor/seq/for_each.hpp> #include <string> #define REALLY_MAKE_STRING(x) #x #define MAKE_STRING(x) REALLY_MAKE_STRING(x) #define MACRO1(r, data, elem) elem, #define MACRO1_STRING(r, data, elem) case elem: return REALLY_MAKE_STRING(elem); #define MACRO1_ENUM(r, data, elem) if (REALLY_MAKE_STRING(elem) == eStrEl) return elem; #define MakeEnum(eName, SEQ) \ enum eName { BOOST_PP_SEQ_FOR_EACH(MACRO1, , SEQ) \ last_##eName##_enum}; \ const int eName##Count = BOOST_PP_SEQ_SIZE(SEQ); \ static std::string eName##2String(const enum eName eel) \ { \ switch (eel) \ { \ BOOST_PP_SEQ_FOR_EACH(MACRO1_STRING, , SEQ) \ default: return"Unknown enumerator value."; \ }; \ }; \ static enum eName eName##2Enum(const std::string eStrEl) \ { \ BOOST_PP_SEQ_FOR_EACH(MACRO1_ENUM, , SEQ) \ return (enum eName)0; \ }; |
有一些限制,公元前的ones之提升::preprocessor。在这情况下,不能进入大名单constants比64的元素。 P / < >
英镑同样的逻辑,你也能想到创造sparse enum: P / < >
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | #define EnumName(Tuple) BOOST_PP_TUPLE_ELEM(2, 0, Tuple) #define EnumValue(Tuple) BOOST_PP_TUPLE_ELEM(2, 1, Tuple) #define MACRO2(r, data, elem) EnumName(elem) EnumValue(elem), #define MACRO2_STRING(r, data, elem) case EnumName(elem): return BOOST_PP_STRINGIZE(EnumName(elem)); #define MakeEnumEx(eName, SEQ) \ enum eName { \ BOOST_PP_SEQ_FOR_EACH(MACRO2, _, SEQ) \ last_##eName##_enum }; \ const int eName##Count = BOOST_PP_SEQ_SIZE(SEQ); \ static std::string eName##2String(const enum eName eel) \ { \ switch (eel) \ { \ BOOST_PP_SEQ_FOR_EACH(MACRO2_STRING, _, SEQ) \ default: return"Unknown enumerator value."; \ }; \ }; |
在这情况下,语法: P / < >
1 2 3 4 5 | MakeEnumEx(TestEnum, ((x,)) ((y,=1000)) ((z,)) ); |
usage也similar级以上(零下的ename # # 2enum功能,你可以试着extrapolate从previous语法)。 P / < >
我的身体它在Mac和Linux,不过是意识的提升,::preprocessor可能不是全便携式。 P / < >
尝试将C++枚举转换为字符串。当枚举项具有任意值时,注释有一些改进可以解决这个问题。
通过合并这里的一些技术,我得出了最简单的形式:
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 | #define MACROSTR(k) #k #define X_NUMBERS \ X(kZero ) \ X(kOne ) \ X(kTwo ) \ X(kThree ) \ X(kFour ) \ X(kMax ) enum { #define X(Enum) Enum, X_NUMBERS #undef X } kConst; static char *kConstStr[] = { #define X(String) MACROSTR(String), X_NUMBERS #undef X }; int main(void) { int k; printf("Hello World! "); for (k = 0; k < kMax; k++) { printf("%s ", kConstStr[k]); } return 0; } |
如果您使用GCC,则可以使用:
1 | const char * enum_to_string_map[]={ [enum1]='string1', [enum2]='string2'}; |
那就打个电话吧
1 | enum_to_string_map[enum1] |
使某个东西同时成为C标识符和字符串
查看MU动力研究实验室的想法-博客档案。今年早些时候我发现了这个——我忘记了我遇到它的确切上下文——并把它改编成了这个代码。我们可以在前面讨论添加e的优点;它适用于所解决的特定问题,但不是一般解决方案的一部分。我把它藏在我的"小插曲"文件夹中——在那里我保存一些有趣的代码片段,以备以后需要。我很不好意思说,当时我没有记录下这个想法是从哪里来的。
标题:Paste1.h
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 | /* @(#)File: $RCSfile: paste1.h,v $ @(#)Version: $Revision: 1.1 $ @(#)Last changed: $Date: 2008/05/17 21:38:05 $ @(#)Purpose: Automated Token Pasting */ #ifndef JLSS_ID_PASTE_H #define JLSS_ID_PASTE_H /* * Common case when someone just includes this file. In this case, * they just get the various E* tokens as good old enums. */ #if !defined(ETYPE) #define ETYPE(val, desc) E##val, #define ETYPE_ENUM enum { #endif /* ETYPE */ ETYPE(PERM, "Operation not permitted") ETYPE(NOENT,"No such file or directory") ETYPE(SRCH, "No such process") ETYPE(INTR, "Interrupted system call") ETYPE(IO, "I/O error") ETYPE(NXIO, "No such device or address") ETYPE(2BIG, "Arg list too long") /* * Close up the enum block in the common case of someone including * this file. */ #if defined(ETYPE_ENUM) #undef ETYPE_ENUM #undef ETYPE ETYPE_MAX }; #endif /* ETYPE_ENUM */ #endif /* JLSS_ID_PASTE_H */ |
实例来源:
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 | /* @(#)File: $RCSfile: paste1.c,v $ @(#)Version: $Revision: 1.2 $ @(#)Last changed: $Date: 2008/06/24 01:03:38 $ @(#)Purpose: Automated Token Pasting */ #include"paste1.h" static const char *sys_errlist_internal[] = { #undef JLSS_ID_PASTE_H #define ETYPE(val, desc) desc, #include"paste1.h" 0 #undef ETYPE }; static const char *xerror(int err) { if (err >= ETYPE_MAX || err <= 0) return"Unknown error"; return sys_errlist_internal[err]; } static const char*errlist_mnemonics[] = { #undef JLSS_ID_PASTE_H #define ETYPE(val, desc) [E ## val] ="E" #val, #include"paste1.h" #undef ETYPE }; #include <stdio.h> int main(void) { int i; for (i = 0; i < ETYPE_MAX; i++) { printf("%d: %-6s: %s ", i, errlist_mnemonics[i], xerror(i)); } return(0); } |
不一定是世界上最干净的使用C预处理器-但它确实阻止了多次写出材料。
1 2 3 4 5 6 7 8 | #define stringify( name ) # name enum MyEnum { ENUMVAL1 }; ...stuff... stringify(EnumName::ENUMVAL1); // Returns MyEnum::ENUMVAL1 |
进一步的discussion在这方法 P / < >
preprocessor指令tricks为newcomers P / < >
我认为,在像融合解决方案的提升。一个给adapting structs和类会好的,即使他们让它在一些点,到使用enums级融合序列。 P / < >
所以我做的只是一些小的宏代码打印到generate"到"enums。这是不完美的,有没有看到与提升。boilerplate融合产生代码,但可以用喜欢的提升融合宏。我真的想做的generate类型需要通过提升到integrate融合。在这个基础设施,allows到打印的名字struct会员,但这将发生以后,现在这只是宏: P / < >
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 | #ifndef SWISSARMYKNIFE_ENUMS_ADAPT_ENUM_HPP #define SWISSARMYKNIFE_ENUMS_ADAPT_ENUM_HPP #include <swissarmyknife/detail/config.hpp> #include <string> #include <ostream> #include <boost/preprocessor/cat.hpp> #include <boost/preprocessor/stringize.hpp> #include <boost/preprocessor/seq/for_each.hpp> #define SWISSARMYKNIFE_ADAPT_ENUM_EACH_ENUMERATION_ENTRY_C( \ R, unused, ENUMERATION_ENTRY) \ case ENUMERATION_ENTRY: \ return BOOST_PP_STRINGIZE(ENUMERATION_ENTRY); \ break; /** * \brief Adapts ENUM to reflectable types. * * \param ENUM_TYPE To be adapted * \param ENUMERATION_SEQ Sequence of enum states */ #define SWISSARMYKNIFE_ADAPT_ENUM(ENUM_TYPE, ENUMERATION_SEQ) \ inline std::string to_string(const ENUM_TYPE& enum_value) { \ switch (enum_value) { \ BOOST_PP_SEQ_FOR_EACH( \ SWISSARMYKNIFE_ADAPT_ENUM_EACH_ENUMERATION_ENTRY_C, \ unused, ENUMERATION_SEQ) \ default: \ return BOOST_PP_STRINGIZE(ENUM_TYPE); \ } \ } \ \ inline std::ostream& operator<<(std::ostream& os, const ENUM_TYPE& value) { \ os << to_string(value); \ return os; \ } #endif |
旧的回答下面很坏,请不要使用,。:) P / < > 旧的回答:
我已经搜索的方式,solves这个问题没有改变太多的enums declaration语法。我来找的解决方案,用途的preprocessor到retrieve字符串从stringified enum declaration。 P / < >
我能到定义的非sparse enums像这样: P / < >
1 2 3 4 5 6 7 | SMART_ENUM(State, enum State { RUNNING, SLEEPING, FAULT, UNKNOWN }) |
我能与他们互动,在不同的方式: P / < >
1 2 3 4 5 6 7 8 9 10 11 12 13 | // With a stringstream std::stringstream ss; ss << State::FAULT; std::string myEnumStr = ss.str(); //Directly to stdout std::cout << State::FAULT << std::endl; //to a string std::string myStr = State::to_string(State::FAULT); //from a string State::State myEnumVal = State::from_string(State::FAULT); |
的基础上的definitions以下: P / < >
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 64 65 66 67 68 69 70 71 | #define SMART_ENUM(enumTypeArg, ...) \ namespace enumTypeArg { \ __VA_ARGS__; \ std::ostream& operator<<(std::ostream& os, const enumTypeArg& val) { \ os << swissarmyknife::enums::to_string(#__VA_ARGS__, val); \ return os; \ } \ \ std::string to_string(const enumTypeArg& val) { \ return swissarmyknife::enums::to_string(#__VA_ARGS__, val); \ } \ \ enumTypeArg from_string(const std::string &str) { \ return swissarmyknife::enums::from_string<enumTypeArg>(#__VA_ARGS__, str); \ } \ } \ namespace swissarmyknife { namespace enums { static inline std::string to_string(const std::string completeEnumDeclaration, size_t enumVal) throw (std::runtime_error) { size_t begin = completeEnumDeclaration.find_first_of('{'); size_t end = completeEnumDeclaration.find_last_of('}'); const std::string identifiers = completeEnumDeclaration.substr(begin + 1, end ); size_t count = 0; size_t found = 0; do { found = identifiers.find_first_of(",}", found+1); if (enumVal == count) { std::string identifiersSubset = identifiers.substr(0, found); size_t beginId = identifiersSubset.find_last_of("{,"); identifiersSubset = identifiersSubset.substr(beginId+1); boost::algorithm::trim(identifiersSubset); return identifiersSubset; } ++count; } while (found != std::string::npos); throw std::runtime_error("The enum declaration provided doesn't contains this state."); } template <typename EnumType> static inline EnumType from_string(const std::string completeEnumDeclaration, const std::string &enumStr) throw (std::runtime_error) { size_t begin = completeEnumDeclaration.find_first_of('{'); size_t end = completeEnumDeclaration.find_last_of('}'); const std::string identifiers = completeEnumDeclaration.substr(begin + 1, end ); size_t count = 0; size_t found = 0; do { found = identifiers.find_first_of(",}", found+1); std::string identifiersSubset = identifiers.substr(0, found); size_t beginId = identifiersSubset.find_last_of("{,"); identifiersSubset = identifiersSubset.substr(beginId+1); boost::algorithm::trim(identifiersSubset); if (identifiersSubset == enumStr) { return static_cast<EnumType>(count); } ++count; } while (found != std::string::npos); throw std::runtime_error("No valid enum value for the provided string"); } }} |
当我需要支援为sparse enum当我会有更多的时间,我会improve * * *从字符串的字符串_ _ implementations与提升::xpressive,但这将成本在编译时间因为英语是重要的templating performed和executable产生也可能真的要更大。但这腹部的优势,它将比这更多的readable和maintanable丑女手册manipulation字符串的代码。D: P / < >
另有)总是用的提升::bimap到执行这样一个mappings之间enums字符串的值的和,但它的肚子要保持manually。 P / < >
由于我不喜欢使用宏的所有常见原因,我使用了一个更有限的宏解决方案,它具有保持枚举声明宏自由的优点。缺点包括必须复制粘贴每个枚举的宏定义,以及在向枚举添加值时必须显式添加宏调用。
1 2 3 4 5 6 7 8 9 10 11 | std::ostream& operator<<(std::ostream& os, provenance_wrapper::CaptureState cs) { #define HANDLE(x) case x: os << #x; break; switch (cs) { HANDLE(CaptureState::UNUSED) HANDLE(CaptureState::ACTIVE) HANDLE(CaptureState::CLOSED) } return os; #undef HANDLE } |
我有一个简单的类,
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 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 | #ifndef STREAMABLE_ENUM_HPP #define STREAMABLE_ENUM_HPP #include <iostream> #include <string> #include <map> template <typename E> class streamable_enum { public: typedef typename std::map<E, std::string> tostr_map_t; typedef typename std::map<std::string, E> fromstr_map_t; streamable_enum() {} streamable_enum(E val) : Val_(val) {} operator E() { return Val_; } bool operator==(const streamable_enum<E>& e) { return this->Val_ == e.Val_; } bool operator==(const E& e) { return this->Val_ == e; } static const tostr_map_t& to_string_map() { static tostr_map_t to_str_(get_enum_strings<E>()); return to_str_; } static const fromstr_map_t& from_string_map() { static fromstr_map_t from_str_(reverse_map(to_string_map())); return from_str_; } private: E Val_; static fromstr_map_t reverse_map(const tostr_map_t& eToS) { fromstr_map_t sToE; for (auto pr : eToS) { sToE.emplace(pr.second, pr.first); } return sToE; } }; template <typename E> streamable_enum<E> stream_enum(E e) { return streamable_enum<E>(e); } template <typename E> typename streamable_enum<E>::tostr_map_t get_enum_strings() { // \todo throw an appropriate exception or display compile error/warning return {}; } template <typename E> std::ostream& operator<<(std::ostream& os, streamable_enum<E> e) { auto& mp = streamable_enum<E>::to_string_map(); auto res = mp.find(e); if (res != mp.end()) { os << res->second; } else { os.setstate(std::ios_base::failbit); } return os; } template <typename E> std::istream& operator>>(std::istream& is, streamable_enum<E>& e) { std::string str; is >> str; if (str.empty()) { is.setstate(std::ios_base::failbit); } auto& mp = streamable_enum<E>::from_string_map(); auto res = mp.find(str); if (res != mp.end()) { e = res->second; } else { is.setstate(std::ios_base::failbit); } return is; } #endif |
usage: P / < > <><>预编码#包括"streamable _ enum.hpp" 使用一个标准::cout; 使用一个标准::CIN; 使用一个标准::endl; enum {动物 猫, 狗, 老虎,老虎, 兔 }; template < > streamable _ enum >:<动物:tostr _地图的_得到_ enum _ <字符串>动物(){ {回报 {"猫,猫是n
下面是一个使用宏的解决方案,具有以下功能:
只写一次枚举的每个值,因此没有要维护的双列表
不要将枚举值保存在以后包含的单独文件中,这样我就可以将其写入任何我想要的地方。
不要替换枚举本身,我仍然希望定义枚举类型,但除此之外,我希望能够将每个枚举名称映射到相应的字符串(不影响旧代码)。
对于那些巨大的枚举,搜索应该很快,所以最好不要使用开关盒。
https://stackoverflow.com/a/20134475/1812866
如果枚举索引基于0,则可以将名称放入char*数组中,并使用枚举值对其进行索引。