能否在C++17中用X-Macro实现std::variant?解决模板尾逗号问题
解决C++17中X-Macro生成std::variant的尾逗号问题
在C17里模板参数确实不支持尾逗号(C20才引入该特性),针对你用X-Macro生成std::variant的场景,有几个靠谱的解决办法:
方法一:拆分X-Macro为首元素与后续元素
调整类型列表的宏定义,区分首个类型和后续类型,让后续类型自动带前置逗号,彻底避免尾逗号:
// 定义拆分式的X-Macro,区分首元素(FIRST)和后续元素(REST) #define LIST_OF_TYPES(FIRST, REST) \ FIRST(Type1) \ REST(Type2) \ REST(Type3) // 生成类型定义:REST和FIRST用同一个宏,直接展开类定义 #define DEFINE_TYPE(name) class name {}; LIST_OF_TYPES(DEFINE_TYPE, DEFINE_TYPE) // 生成variant参数:REST使用带前置逗号的宏,首元素不带逗号 #define VARIANT_ITEM(name) name #define VARIANT_REST_ITEM(name) , name using MyVariant = std::variant<LIST_OF_TYPES(VARIANT_ITEM, VARIANT_REST_ITEM)>;
这种方式只需要维护一个类型列表,同时适配类型定义和variant参数两种场景,没有多余的语法问题,兼容性最好。
方法二:借助元编程中转类型列表
先通过X-Macro生成std::tuple的类型列表,再用模板元编程把tuple转成variant:
#include <tuple> #include <variant> #define LIST_OF_TYPES(X) \ X(Type1) \ X(Type2) \ X(Type3) #define MAKE_TYPE(name) class name {}; LIST_OF_TYPES(MAKE_TYPE) #undef MAKE_TYPE // 定义tuple类型列表(可复用方法一的方式生成,避免手动写) using TypeTuple = std::tuple<Type1, Type2, Type3>; // 模板元编程将tuple转为variant template<typename Tuple> struct TupleToVariant; template<typename... Ts> struct TupleToVariant<std::tuple<Ts...>> { using type = std::variant<Ts...>; }; using MyVariant = typename TupleToVariant<TypeTuple>::type;
这种方式适合已经有类型元组的场景,缺点是需要额外写元编程代码,不如方法一直接。
方法三:预处理器宏消除尾逗号(不推荐)
可以用复杂的预处理器宏技巧“吃掉”尾逗号,但这种方式依赖编译器预处理器的行为,兼容性较差:
// 辅助宏用于移除尾逗号 #define REMOVE_TRAILING_COMMA(...) _REMOVE_TRAILING_COMMA_HELPER(__VA_ARGS__,) #define _REMOVE_TRAILING_COMMA_HELPER(a, ...) __VA_ARGS__ #define LIST_OF_TYPES(X) \ X(Type1) \ X(Type2) \ X(Type3) #define MAKE_TYPE(name) class name {}; LIST_OF_TYPES(MAKE_TYPE) #undef MAKE_TYPE #define MAKE_VARIANT(name) name, using MyVariant = std::variant<REMOVE_TRAILING_COMMA(LIST_OF_TYPES(MAKE_VARIANT))>;
这个方法虽能工作,但不同编译器的预处理器对可变参数宏的处理可能有差异,不建议在生产代码中使用。
内容的提问来源于stack exchange,提问作者auzn
相关产品推荐
相关产品推荐

