我已经写了一些实用程序宏来将enum
值转换为std::string
:
#include <map>
#include <string>
#define MY_map_entry_(name, value) {#value, name::value}
#define MY_map_2(name, v1, v2) MY_map_entry_(name, v1), MY_map_entry_(name, v2)
#define MY_map_3(name, v1, v2, v3) MY_map_entry_(name, v1), MY_map_2(name, v2, v3)
这完全按预期工作:
enum class rgb { red, green, blue };
static const std::map<std::string, rgb> string_to_rgb{ MY_map_3(rgb, red, green, blue) };
// { {"red", rgb::red}, {"green", rgb::green}, {"blue", rgb::blue} }
然而,它开始变得有点乏味的编写宏;所以我想试试__VA_ARGS__
#define MY_map_4(name, v1, ...) MY_map_entry_(name, v1), MY_map_3(name, __VA_ARGS__)
用例为
enum class cymk { cyan, yellow, magenta, black };
static const std::map<std::string, cymk> string_to_cymk{ MY_map_4(cymk, cyan, yellow, magenta, black) };
这不起作用,没有__VA_ARGS__
的类似宏可以
#define MY_map_4(name, v1, v2, v3, v4) MY_map_entry_(name, v1), MY_map_3(name, v2, v3, v4)
有没有办法用__VA_ARGS__
来写MY_map_4
?
(当然,在不使用任何宏的情况下这样做会很好,或者至少接近;但我认为那是不可能的。
您实际需要的是x -宏而不是可变宏:
#define ENUM_VAL(X) X
#define ENUM_TO_STRING(E, X) {E::X, #X}
#define STRING_TO_ENUM(E, X) {#X, E::X}
enum class rgb
{
#define RGB_VALS E(red), E(green), E(blue)
#define E(X) ENUM_VAL(X)
RGB_VALS
#undef E
};
static const std::map<rgb, std::string> rgb_to_string
({
#define E(X) ENUM_TO_STRING(rgb, X)
RGB_VALS
#undef E
});
static const std::map<std::string, rgb> string_to_rgb
({
#define E(X) STRING_TO_ENUM(rgb, X)
RGB_VALS
#undef E
});
#undef RGB_VALS
背后的思想是:在从属宏中定义枚举值,该从属宏使用helper宏实际生成代码。
使用辅助宏,您可以交换从属宏的行为,并获得不同上下文所需的结果。
你的宏没有任何问题。GCC和Clang接受它的开箱即用,而MSVC需要/Zc:preprocessor
(它支持标准一致性的预处理器;默认预处理器有bug)。
宏可以改进为支持无限枚举大小(不需要显式指定),并声明枚举和数组。这里有一个例子。(需要c++ 20, Clang额外需要-Wno-gnu-zero-variadic-macro-arguments
。MSVC要求/Zc:preprocessor
.)
#define ENUM(name, seq)
enum class name { END(ENUM_DECL_A seq) };
std::pair<std::string, name> CAT(name, _values)[] = { END(ENUM_ARR_A seq) };
#define END(...) END_(__VA_ARGS__)
#define END_(...) __VA_ARGS__##_END
#define CAT(x, y) CAT_(x, y)
#define CAT_(x, y) x##y
#define STR(...) STR_(__VA_ARGS__)
#define STR_(...) #__VA_ARGS__
#define ENUM_DECL_A(...) ENUM_DECL_BODY(__VA_ARGS__) ENUM_DECL_B
#define ENUM_DECL_B(...) ENUM_DECL_BODY(__VA_ARGS__) ENUM_DECL_A
#define ENUM_DECL_A_END
#define ENUM_DECL_B_END
#define ENUM_DECL_BODY(name, ...) name __VA_OPT__(= __VA_ARGS__),
#define ENUM_ARR_A(...) ENUM_ARR_BODY(__VA_ARGS__) ENUM_ARR_B
#define ENUM_ARR_B(...) ENUM_ARR_BODY(__VA_ARGS__) ENUM_ARR_A
#define ENUM_ARR_A_END
#define ENUM_ARR_B_END
#define ENUM_ARR_BODY(name, ...) STR(name),
然后,ENUM(A, (x)(y,42)(z))
展开为:
enum class A
{
x,
y = 42,
z,
};
std::pair<std::string, A> A_values[] = { "x", "y", "z", };