问题描述
我正在尝试为 str 宏实现一个适当的枚举,这将自动化枚举值与其在代码中的名称之间的关联。
例如,我想定义一个名为“Test”的新宏,如下所示:
ENUM_STR_DECLARE(Test,1,test1,test2,test3)
这样,通过调用 TestEnumToString(test2)
,我可以访问字符串 "test2"
。目前,我目前对这个 ENUM_STR_DECLARE
的实现如下:
#define ENUM_STR_DECLARE(enumName,intOffset,v1,...)\
enum enumName { v1 = intOffset,__VA_ARGS__};\
const char *enumName##EnumStringArray[] = { #v1,#__VA_ARGS__};\
const char *enumName##EnumToString(value) { return enumName##EnumStringArray[ value - offset ]; }
虽然当我这样做时,__VA_ARGS__
处理的枚举没有得到正确的名称分隔:
enum Test {
test1 = 1,test3
};
const char *TestEnumStringArray[] = {"test1","test2,test3"};
const char *TestEnumToString(value) { return TestEnumStringArray[ value - offset]; }
因为我想要 "test2","test3"
而不是 "test2,test3"
。
有没有办法用逗号分隔扩展 #__VA_ARGS__
名称?
干杯!
编辑:一个变通办法
这个问题似乎没有简单/优雅的解决方案。迄今为止最好的实现是由@h-walters 提出的,它提供了一个非常详细的实现分解(感谢您的时间!)。这是他为感兴趣的人分享的链接: H. Walters example。
然而,即使这个实现似乎也必须限制您定义的枚举数量(在他的情况下为 9)。所以对我来说,解决方法是最终的答案。
与其费力寻找切片 __VA_ARGS__
的方法,不如像我一样简单地将整个 __VA_ARGS__
字符串化,并在每次我们想要获取特定枚举的名称时对获得的字符串进行切片。显然,这是一种较慢的方法,因为它每次都需要解析整个字符串,而不是直接使用枚举索引获取。
这个速度问题与我无关,因为枚举到字符串的转换旨在用于显示目的,否则枚举将直接用于耗时的例程。如果您在获得字符串翻译时仍然想要快速,您可以利用可以在您第一次调用 toString() 方法时构建的缓存(例如 std::vector<std::string>
)。或者,您可以使用 @h-walters 解决方案,这是最快的,知道其局限性。
话不多说,这是我最终得到的解决方案:
#define VA_TO_STR(...) #__VA_ARGS__
#define ENUM_STR_DECLARE(enumName_,intOffset_,v1_,...)\
enum enumName_ { v1_ = intOffset_,__VA_ARGS__,enumName_##_OVERFLOW };\
namespace enumName_##EnumNamespace{\
const char *enumNamesAgregate = VA_TO_STR(v1_,__VA_ARGS__); \
int enumOffSet = intOffset_; \
std::string toString(int enumValue_) {\
int commaCounter = 0; std::string outStr;\
for( unsigned long iChar = 0 ; iChar < strlen(enumNamesAgregate) ; iChar++ ){ \
if( enumNamesAgregate[iChar] == ',' ){\
if( not outStr.empty() ){ return outStr; } /* found! return */\
else{ commaCounter++; iChar += 2; } /* not yet found,next */ \
}\
if( commaCounter == enumValue_ ){ outStr += enumNamesAgregate[iChar]; }\
}\
return outStr;\
}\
std::string toString(enumName_ enumValue_){ return enumName_##EnumNamespace::toString(static_cast<int>(enumValue_)); }\
int toEnumInt(const std::string& enumStr_){\
for( int enumIndex = intOffset_ ; enumIndex < enumName_::enumName_##_OVERFLOW ; enumIndex++ ){ \
if( enumName_##EnumNamespace::toString(enumIndex) == enumStr_ ){ return enumIndex; } \
}\
return intOffset_ - 1; /* returns invalid value */\
}\
enumName_ toEnum(const std::string& enumStr_){ return static_cast<enumName_>(enumName_##EnumNamespace::toEnumInt(enumStr_)); }\
}
因此,我上面介绍的简单示例将展开为:
enum Test {
test1 = 1,test3,Test_OVERFLOW
};
namespace TestEnumNamespace {
const char *enumNamesAgregate = "test1,test3";
int enumOffSet = 1;
std::string toString(int enumValue_) {
int commaCounter = 0;
std::string outStr;
for (unsigned long iChar = 0; iChar < strlen(enumNamesAgregate); iChar++) {
if (enumNamesAgregate[iChar] == ',') {
if (notoutStr.empty()) { return outStr; }
else {
commaCounter++;
iChar += 2;
}
}
if (commaCounter == enumValue_) { outStr += enumNamesAgregate[iChar]; }
}
return outStr;
}
std::string toString(Test enumValue_) { return TestEnumNamespace::toString(static_cast<int>(enumValue_)); }
int toEnumInt(const std::string &enumStr_) {
for (int enumIndex = 1; enumIndex < Test::Test_OVERFLOW; enumIndex++) {
if (TestEnumNamespace::toString(enumIndex) == enumStr_) { return enumIndex; }
}
return 1 - 1;
}
Test toEnum(const std::string &enumStr_) { return static_cast<Test>(TestEnumNamespace::toEnumInt(enumStr_)); }
}
让我们说,如果你想得到枚举“test1”的字符串:
TestEnumNamespace::toString(Test::test1);
TestEnumNamespace::toEnum("test1");
希望它能帮助其他开发者:)
再次干杯!
解决方法
暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!
如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。
小编邮箱:dio#foxmail.com (将#修改为@)