根据字符串表示设置枚举值

时间:2016-01-22 11:24:39

标签: c++ string enums

我有一个包含枚举字符串表示的配置文件。有很多不同的枚举值。加载配置后,我需要从字符串表示中计算出枚举值。忽略宏,我能想到的唯一方法就是创建一个可怕的查找函数,对每个可能的值进行字符串比较。类似的东西:

typedef enum Fields
{
  FieldFlagNone,
  FieldFlagOperation,
  FieldFlagFormat,
  ...
}


Fields getFieldEnum(string fieldName){
  if( fieldName.compare("FieldFlagNone") == 0 ){
    return FieldFlagNone;
  }else if( fieldName.compare("FieldFlagOperation") == 0 ){
    return FieldFlagOperation;
  }else if( fieldName.compare("FieldFlagFormat") == 0 ){
    return FieldFlagFormat;
  ...
}

是否有更快或更简洁的方法来达到预期效果?

1 个答案:

答案 0 :(得分:2)

您可以使用std::unordered_map<std::string, Fields>,这将加快从线性时间到恒定时间的转换:

std::unordered_map<std::string, Fields> fieldsLookupTable {
    { "FieldFlagNone", FieldFlagNone },
    ...
};

为了使其更简洁,您可以使用一些宏:

#define LOOKUP_TABLE_ENTRY(x) { #x, x }

然后:

std::unordered_map<std::string, Fields> fieldsLookupTable {
    LOOKUP_TABLE_ENTRY(FieldFlagNone),
    LOOKUP_TABLE_ENTRY(FieldFlagOperation),
    ...
};

如果你想真正去消除重复,你可以这样做:

#define ENUM_MODE_DEFINE 0
#define ENUM_MODE_LOOKUP 1

#define ENUM_BEGIN(x) \
#if ENUM_MODE == ENUM_MODE_DEFINE \
typedef enum x { \
#else \
#define LOOKUP_TABLE_NAME x ## LookupTable \
std::unordered_map<std::string, x> LOOKUP_TABLE_NAME; \
#endif

#define ENUM_ENTRY(x) \
#if ENUM_MODE == ENUM_MODE_DEFINE \
x, \
#else \
LOOKUP_TABLE_NAME[#x] = x; \
#endif

#define ENUM_END \
#if ENUM_MODE == ENUM_MODE_DEFINE \
} \
#else \
#undef LOOKUP_TABLE_NAME \
#endif

然后像这样定义你的枚举:

#define FIELDS \
ENUM_BEGIN(Fields) \
ENUM_ENTRY(FieldFlagNone) \
ENUM_ENTRY(FieldFlagOperation) \
...
ENUM_END

以前有枚举定义,现在会有:

#define ENUM_MODE ENUM_MODE_DEFINE
FIELDS

在你拥有查找表的其他地方,你这样说:

#define ENUM_MODE ENUM_MODE_LOOKUP
FIELDS

FIELDS宏基本上使用ENUM_BEGINENUM_ENTRYENUM_END宏,它们会根据ENUM_MODE的值生成不同的代码。如果您将其定义为ENUM_MODE_DEFINE,则FIELDS将生成枚举定义。如果您将其设置为ENUM_MODE_LOOKUP,则会生成fieldsLookupTable。 这样我们只使用FIELDS中的枚举条目名称,因此如果你在那里更改某些内容,查找表和枚举定义将自动更改,不会不同步。