如何将可变参数宏__VA_ARGS__的每个令牌字符串化以生成枚举与字符串向量?
解决方案
一、基于Boost.Preprocessor的实现
Boost.Preprocessor提供了成熟的可变参数遍历工具,无需手动定义大量解析宏即可完成需求,代码简洁且可维护性高。
完整代码示例
#include <vector> #include <string> #include <boost/preprocessor/seq/for_each.hpp> #include <boost/preprocessor/variadic/to_seq.hpp> #include <boost/preprocessor/stringize.hpp> // 辅助宏:将单个令牌转换为带逗号的字符串字面量,适配vector初始化语法 #define STRINGIZE_ITEM(r, unused, elem) BOOST_PP_STRINGIZE(elem), // 主宏:生成指定名称的枚举和对应的字符串向量 #define MAKE_ENUM_AND_STRINGS(ENUM_NAME, ...) \ enum class ENUM_NAME { __VA_ARGS__ }; \ std::vector<std::string> ENUM_NAME##_strings { \ BOOST_PP_SEQ_FOR_EACH(STRINGIZE_ITEM, _, BOOST_PP_VARIADIC_TO_SEQ(__VA_ARGS__)) \ } // 使用示例 void foo() { MAKE_ENUM_AND_STRINGS(test_enum, a, b, c, d); // 验证枚举值与向量索引的对应关系 static_assert(static_cast<int>(test_enum::a) == 0); static_assert(test_enum_strings[0] == "a"); static_assert(static_cast<int>(test_enum::d) == 3); static_assert(test_enum_strings[3] == "d"); }
工作逻辑
BOOST_PP_VARIADIC_TO_SEQ(__VA_ARGS__):将输入的可变参数列表(a,b,c,d)转换为Boost预处理器序列(a)(b)(c)(d);BOOST_PP_SEQ_FOR_EACH:遍历序列中的每个元素,对每个元素调用STRINGIZE_ITEM宏;STRINGIZE_ITEM:通过BOOST_PP_STRINGIZE将令牌转换为字符串字面量,并自动添加逗号,适配vector初始化列表的语法要求。
二、C20/C23原生方案(无需Boost)
C++20:结合__VA_OPT__与constexpr数组
C++20的__VA_OPT__可处理可变参数的逗号边界问题,配合模板可实现无依赖的解决方案:
#include <vector> #include <string> #include <array> // 模板类:将枚举令牌打包为constexpr字符串数组 template <auto... EnumItems> struct EnumStringPack { static constexpr std::array<const char*, sizeof...(EnumItems)> values = {#EnumItems...}; }; #define MAKE_ENUM_AND_STRINGS(ENUM_NAME, ...) \ enum class ENUM_NAME { __VA_ARGS__ }; \ inline constexpr auto ENUM_NAME##_str_array = EnumStringPack<__VA_ARGS__>::values; \ std::vector<std::string> ENUM_NAME##_strings(ENUM_NAME##_str_array.begin(), ENUM_NAME##_str_array.end()) // 使用示例 void bar() { MAKE_ENUM_AND_STRINGS(my_enum, x, y, z); static_assert(my_enum_strings[0] == "x"); }
C++23:反射特性(实验性)
C++23的std::meta反射库(当前仅GCC 13+、Clang 17+部分支持)可直接枚举枚举成员并获取名称,完全摆脱预处理器宏:
#include <vector> #include <string> #include <meta> // 通用函数:将枚举类型转换为字符串向量 template <typename EnumType> std::vector<std::string> enum_to_strings() { std::vector<std::string> result; for (auto member : std::meta::members_of<EnumType>()) { result.push_back(std::meta::name_of(member)); } return result; } // 使用示例 enum class color { red, green, blue }; void baz() { auto color_strings = enum_to_strings<color>(); // color_strings == {"red", "green", "blue"} }
注意:该特性目前处于实验阶段,需启用编译器扩展(如GCC加-freflection,Clang加-std=c++23 -freflection),尚未完全标准化。
内容的提问来源于stack exchange,提问作者PinkTurtle
相关产品推荐
相关产品推荐

