C++命名宏参数与__VA_ARGS__区别及枚举转字符串宏实现方法
错误原因
你编写的__VA_ARGS__版本MY_map_4无法正常运行的核心原因是:C++预处理器默认会将__VA_ARGS__整体视为单个参数传递给下层宏,导致MY_map_3无法匹配到所需的3个入参,宏展开失败。
宏修复方案
仅修复MY_map_4
增加一个辅助宏强制展开可变参数即可,修改后的宏定义如下:
// 辅助宏:强制展开参数传递给目标宏 #define MY_CALL_MACRO(macro, ...) macro(__VA_ARGS__) // 修复后的MY_map_4 #define MY_map_4(name, v1, ...) MY_map_entry_(name, v1), MY_CALL_MACRO(MY_map_3, name, __VA_ARGS__)
修改后你的原有调用代码可以正常编译运行,生成预期的映射关系。
通用可变参数版本(无需手动编写N个MY_map_N宏)
如果要支持任意数量的枚举值,不需要每次手动新增对应参数数量的宏,可以通过可变参数计数实现通用版本:
#include <map> #include <string> #define MY_map_entry_(name, value) {#value, name::value} // 参数计数辅助宏,最多支持32个枚举值,可按需扩展 #define MY_GET_ARG_COUNT(_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, COUNT,...) COUNT #define MY_ARG_COUNT(...) MY_GET_ARG_COUNT(__VA_ARGS__,32,31,30,29,28,27,26,25,24,23,22,21,20,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1) #define MY_CONCAT_IMPL(a,b) a##b #define MY_CONCAT(a,b) MY_CONCAT_IMPL(a,b) // 通用展开宏 #define MY_MAP_GEN(name, count, ...) MY_CONCAT(MY_map_, count)(name, __VA_ARGS__) #define MY_ENUM_MAP(name, ...) { MY_MAP_GEN(name, MY_ARG_COUNT(__VA_ARGS__), __VA_ARGS__) } // 对应参数数量的展开宏,可按需扩展 #define MY_map_1(name, v1) MY_map_entry_(name, v1) #define MY_map_2(name, v1, v2) MY_map_entry_(name, v1), MY_map_1(name, v2) #define MY_map_3(name, v1, v2, v3) MY_map_entry_(name, v1), MY_map_2(name, v2, v3) #define MY_map_4(name, v1, v2, v3, v4) MY_map_entry_(name, v1), MY_map_3(name, v2, v3, v4) #define MY_map_5(name, v1, ...) MY_map_entry_(name, v1), MY_CONCAT(MY_map_, MY_ARG_COUNT(__VA_ARGS__))(name, __VA_ARGS__) // 更多MY_map_N可按上述规则扩展
使用方式更简洁,不需要手动指定参数数量:
enum class rgb { red, green, blue }; static const std::map<std::string, rgb> string_to_rgb = MY_ENUM_MAP(rgb, red, green, blue); enum class cymk { cyan, yellow, magenta, black }; static const std::map<std::string, cymk> string_to_cymk = MY_ENUM_MAP(cymk, cyan, yellow, magenta, black);
无宏实现方案
截止C++20标准,原生还没有支持枚举值遍历的静态反射特性,所以自己实现该需求暂时无法完全脱离宏。如果可以引入第三方纯头文件库,有成熟的实现方案可以完全不用宏完成enum/string的双向转换,编译期计算无运行时开销,还支持自定义枚举值、枚举值范围等特性。
内容的提问来源于stack exchange,提问作者user16538449
相关产品推荐
相关产品推荐

