我想做的是:
typedef enum { ONE, TWO, THREE } Numbers;
我正在尝试编写一个函数,它将执行类似于以下内容的切换案例:
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:
// 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:
#include"enumFactory.h"
#define SOME_ENUM(XX) \
XX(FirstValue,) \
XX(SecondValue,) \
XX(SomeOtherValue,=50) \
XX(OneMoreValue,=100) \
DECLARE_ENUM(SomeEnum,SOME_ENUM)
CPP:
#include"someEnum.h"
DEFINE_ENUM(SomeEnum,SOME_ENUM)
这项技术可以很容易地扩展,以便xx宏接受更多的参数,您还可以准备更多的宏来代替xx以满足不同的需要,类似于我在这个示例中提供的三个。使用include/define/undef与X宏进行比较
虽然这类似于其他人提到的X宏,但我认为这个解决方案更优雅,因为它不需要取消任何东西的标记,这允许您隐藏更多复杂的东西在工厂中头文件-头文件是您在需要定义新枚举时根本不接触的东西,因此新枚举澄清要短得多,而且要干净得多。
我在C:abissell.com/2014/01/16/…的一篇关于通用编程的博客文章中引用了这种技术。
我不知道你怎么能说这比X宏更好/更差-这是X宏。SOME_ENUM(XX)正是一个x宏(确切地说,是传递XX函数而不是使用#def#undef函数的"用户窗体"),然后依次传递整个x宏来定义使用它的枚举。不要从解决方案中拿走任何东西——它工作得很好。只是为了说明这是X宏的一种用法。
@因此,您注意到的差异是显著的,并将此解决方案与惯用的X宏(如维基百科的示例)区分开来。通过XX的优势在于前者可以用于宏观扩张。注意,只有像这一个这样简洁的其他解决方案才需要创建并多次包含一个单独的文件来定义一个新的枚举。
另一个技巧是使用枚举名作为宏名。您只需编写#define DEFINE_ENUM(EnumType) ...,用EnumType(...)替换ENUM_DEF(...),让用户说出#define SomeEnum(XX) ...。C预处理器在上下文中将SomeEnum扩展到宏调用中,后面跟括号,否则扩展到常规标记中。(当然,如果用户喜欢使用SomeEnum(2)来强制转换为枚举类型,而不是使用(SomeEnum)2或static_cast(2),则会导致问题。)
@pmttavara-当然,如果快速搜索是最常用的X宏使用固定的内部宏名称,那么除了#define和#undef外,其他宏名称也都是固定的。尽管"用户表单"(如本文底部所建议的)是一种X宏,您是否不同意?我当然也一直把它叫做x宏,在我最近使用的c代码库中,它是最常见的形式(这显然是一种有偏见的观察)。不过,我可能分析错误的操作。
例如,我使用include/define/undef将X宏的比较解释为"此技术(不是X宏)与X宏技术的比较"(关于define/undef的注释仅作为X宏使用方式的描述符)。我看到它也可以被解析为"x-macros变量与x-macros变量的比较,x-macros变量没有将宏作为参数传递,而是使用多个include"。在后一种情况下,我没有问题——这只是一个措辞可能稍微不清楚的问题!
@现在的措辞是编辑的结果,因为你当时说服我这是X宏,即使它可能是当时使用较少的形式(或至少在文章中少提到一种形式)。
@相扑-好了,历史现在有意义了。在我最初的评论中,我本来打算把文章链接回去的,但是忘了。这里的"用户表单"是Andrescu提供的,但是我没有找到它的来源(也许它是直接推荐给作者的)。用最新的措辞,你可以忽略我最初的评论。
// 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
这就是CPP的目的。+ 1。
这是一个很好的答案,它似乎是关于一个人不使用特殊工具可以做的最好的事情,我以前做过这种事情;但它仍然没有真正的感觉"正确",我从来没有真正喜欢做它…
小改动:defs.h文件中的#define ENUM_END(typ) }; extern const char * typ ## _name_table[];—这将在您使用的文件中声明您的名称表。(虽然找不到一个好的方法来声明表的大小。)另外,我个人也会去掉最后的分号,但两者的优点都是有争议的。
另请参见:journal.stuffwithstufacture.com/2012/01/24/higher-order macros in‌&8203;-c
@比尔,干嘛要管typ在#define ENUM_END(typ) };那一行?
如果我希望将宏定义为"one=5",则此操作不起作用。
确实有一种方法可以做到这一点——使用x()宏。这些宏使用C预处理器从源数据列表中构造枚举、数组和代码块。您只需要向包含x()宏的定义中添加新项。switch语句将自动展开。
您的示例可以写如下:
// 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宏创建字符串数组和枚举索引),但这是最简单的演示。
没有内置的解决方案。最简单的方法是使用char*数组,其中枚举的int值索引到包含该枚举的描述性名称的字符串。如果您有一个稀疏的enum(一个不是从0开始,或者在编号上有间隙),其中一些int映射足够高,使得基于数组的映射不实用,那么您可以使用哈希表来代替。
在此基础上展开,如果它确实是一个线性递增的列表,您可以使用编辑器的宏工具来记录每个名称并将其解析为一个字符串。只需要一点点额外的输入,您就可以从一开始就不需要定义了。我单击复制的最后一个宏上的"录制",在后面添加一个引号,然后继续到下一行的同一位置。我推停。我按运行x次,做了很多(或只是一步)。然后我可以将它包装成一个字符串数组。
我知道你有几个很可靠的答案,但是你知道C预处理器中的运算符吗?
它允许您这样做:
#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]);
}
char const *kConstStr[]
的吻。你会做所有的sorts之其他开关/案例的事情与你的enums所以为什么要印刷在不同的吗?forgetting的情况下在你的打印routine是不是问题的huge新政",当你认为有意义的地方,你可以忘记其他100的案例。只是compile墙,将警告美国非exhaustive matches案例。不要用"违约",因为这将使开关exhaustive和你得到warnings韩元。代替,把开关和退出交易与违约的情况下,像这样… P / < >
const char *myenum_str(myenum e)
{
switch(e) {
case ONE: return"one";
case TWO: return"two";
}
return"invalid";
}
C或C++不提供这个功能,虽然我经常需要它。
下面的代码可以工作,尽管它最适合非稀疏枚举。
typedef enum { ONE, TWO, THREE } Numbers;
char *strNumbers[] = {"one","two","three"};
printf ("Value for TWO is %s
",strNumbers[TWO]);
我指的是不稀疏的形状
typedef enum { ONE, FOUR_THOUSAND = 4000 } Numbers;
因为这其中有巨大的差距。
这个方法的优点是,它将枚举和字符串的定义放在一起;在函数中有一个switch语句可以将它们放在一起。这意味着你不太可能改变其中一个。
*使用的提升:尽可能让一个解决方案:preprocessor elegant喜欢以下: P / < >
步骤1:包括同步头文件: P / < >
#include"EnumUtilities.h"
步骤2:enumeration声明的对象与以下语法: P / < >
MakeEnum( TestData,
(x)
(y)
(z)
);
步骤3:使用你的数据: P / < >
得到一些的元素: P / < >
td::cout <
得到的字符串:"美联社 P / < >
std::cout <
std::cout <
std::cout <
我每天早晨的enum值从字符串:美联社 P / < >
std::cout <
std::cout <
std::cout <
这看起来干净和紧凑,与没有额外的文件包括。 "code)写在enumutilities.h的以下: P / < >
#include
#include
#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 / < >
#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 / < >
MakeEnumEx(TestEnum,
((x,))
((y,=1000))
((z,))
);
usage也similar级以上(零下的ename # # 2enum功能,你可以试着extrapolate从previous语法)。 P / < >
我的身体它在Mac和Linux,不过是意识的提升,::preprocessor可能不是全便携式。 P / < >
尝试将C++枚举转换为字符串。当枚举项具有任意值时,注释有一些改进可以解决这个问题。
通过合并这里的一些技术,我得出了最简单的形式:
#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,则可以使用:
const char * enum_to_string_map[]={ [enum1]='string1', [enum2]='string2'};
那就打个电话吧
enum_to_string_map[enum1]
使某个东西同时成为C标识符和字符串
查看MU动力研究实验室的想法-博客档案。今年早些时候我发现了这个——我忘记了我遇到它的确切上下文——并把它改编成了这个代码。我们可以在前面讨论添加e的优点;它适用于所解决的特定问题,但不是一般解决方案的一部分。我把它藏在我的"小插曲"文件夹中——在那里我保存一些有趣的代码片段,以备以后需要。我很不好意思说,当时我没有记录下这个想法是从哪里来的。
标题:Paste1.h
/*
@(#)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 */
实例来源:
/*
@(#)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
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预处理器-但它确实阻止了多次写出材料。
#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 / < >
#ifndef SWISSARMYKNIFE_ENUMS_ADAPT_ENUM_HPP
#define SWISSARMYKNIFE_ENUMS_ADAPT_ENUM_HPP
#include
#include
#include
#include
#include
#include
#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<
os << to_string(value); \
return os; \
}
#endif
旧的回答下面很坏,请不要使用,。:) P / < > 旧的回答:
我已经搜索的方式,solves这个问题没有改变太多的enums declaration语法。我来找的解决方案,用途的preprocessor到retrieve字符串从stringified enum declaration。 P / < >
我能到定义的非sparse enums像这样: P / < >
SMART_ENUM(State,
enum State {
RUNNING,
SLEEPING,
FAULT,
UNKNOWN
})
我能与他们互动,在不同的方式: P / < >
// 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 / < >
#define SMART_ENUM(enumTypeArg, ...) \
namespace enumTypeArg { \
__VA_ARGS__; \
std::ostream& operator<
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(#__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
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(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 / < >
由于我不喜欢使用宏的所有常见原因,我使用了一个更有限的宏解决方案,它具有保持枚举声明宏自由的优点。缺点包括必须复制粘贴每个枚举的宏定义,以及在向枚举添加值时必须显式添加宏调用。
std::ostream& operator<
{
#define HANDLE(x) case x: os << #x; break;
switch (cs) {
HANDLE(CaptureState::UNUSED)
HANDLE(CaptureState::ACTIVE)
HANDLE(CaptureState::CLOSED)
}
return os;
#undef HANDLE
}
我有一个简单的类,streamable_enum雅templated用途的流<>和也的基础上std::map: P / < >
#ifndef STREAMABLE_ENUM_HPP
#define STREAMABLE_ENUM_HPP
#include
#include
#include
template
class streamable_enum
{
public:
typedef typename std::map tostr_map_t;
typedef typename std::map<:string e> fromstr_map_t;
streamable_enum()
{}
streamable_enum(E val) :
Val_(val)
{}
operator E() {
return Val_;
}
bool operator==(const streamable_enum& 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());
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
streamable_enum stream_enum(E e) {
return streamable_enum(e);
}
template
typename streamable_enum::tostr_map_t get_enum_strings() {
// \todo throw an appropriate exception or display compile error/warning
return {};
}
template
std::ostream& operator< e) {
auto& mp = streamable_enum::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
std::istream& operator>>(std::istream& is, streamable_enum& e) {
std::string str;
is >> str;
if (str.empty()) {
is.setstate(std::ios_base::failbit);
}
auto& mp = streamable_enum::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 >:动物(){ {回报 {"猫,猫是n
下面是一个使用宏的解决方案,具有以下功能:
只写一次枚举的每个值,因此没有要维护的双列表
不要将枚举值保存在以后包含的单独文件中,这样我就可以将其写入任何我想要的地方。
不要替换枚举本身,我仍然希望定义枚举类型,但除此之外,我希望能够将每个枚举名称映射到相应的字符串(不影响旧代码)。
对于那些巨大的枚举,搜索应该很快,所以最好不要使用开关盒。
https://stackoverflow.com/a/20134475/1812866
如果枚举索引基于0,则可以将名称放入char*数组中,并使用枚举值对其进行索引。