You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将可变参数宏__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");
}

工作逻辑

  1. BOOST_PP_VARIADIC_TO_SEQ(__VA_ARGS__):将输入的可变参数列表(a,b,c,d)转换为Boost预处理器序列(a)(b)(c)(d);
  2. BOOST_PP_SEQ_FOR_EACH:遍历序列中的每个元素,对每个元素调用STRINGIZE_ITEM宏;
  3. 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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.01 11:01:30