我希望在c++17中使用X-macro来完成以下操作,但由于template参数不支持尾随逗号,因此它不适用于std::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
std::variant<
#define MAKE_VARIANT(name) name,
LIST_OF_TYPES(MAKE_VARIANT)
#undef MAKE_VARIANT
>
是的,有一个解决方法:
#define EMPTY(...)
#define IDENTITY(...) __VA_ARGS__
#define IDENTITY2(...) __VA_ARGS__
std::variant<
#define MAKE_VARIANT(name) (,) name IDENTITY
IDENTITY2(EMPTY LIST_OF_TYPES(MAKE_VARIANT) () )
#undef MAKE_VARIANT
>
如果没有IDENTITY2(...)
,这将扩展到EMPTY(,) Type1 IDENTITY(,) Type2 IDENTITY(,) Type3 IDENTITY()
。IDENTITY2
迫使它再次扩展,这次扩展到Type1, Type2, Type3
。
或者,使用我自己的宏循环库:
在gcc.godbolt.org上运行
#include <macro_sequence_for.h>
#define LIST_OF_TYPES (Type1)(Type2)(Type3)
#define DECLARE_CLASSES(seq) SF_FOR_EACH(DECLARE_CLASSES_BODY, SF_NULL, SF_NULL,, seq)
#define DECLARE_CLASSES_BODY(n, d, x) class x {};
#define MAKE_VARIANT(seq) std::variant<SF_FOR_EACH(MAKE_VARIANT_BODY, USE_COMMA, SF_NULL, EMPTY, seq)>
#define MAKE_VARIANT_BODY(n, d, x) d() x
#define EMPTY(...)
#define COMMA(...) ,
#define USE_COMMA(n, d, x) COMMA
DECLARE_CLASSES(LIST_OF_TYPES) // class Type1 {}; class Type2 {}; class Type3 {};
MAKE_VARIANT(LIST_OF_TYPES) // std::variant<Type1, Type2, Type3>
稍微有点冗长,但在我的口味上更可读。
这里,为每个元素调用#define MAKE_VARIANT_BODY(n, d, x) d() x
,其中x
是元素,并且d
最初设置为EMPTY
(SF_FOR_EACH()
的第四个自变量(。在第一次(以及任何后续(迭代之后,d
被重新分配给USE_COMMA(...)
(也称为COMMA
(,因此从第二次迭代开始,d()
扩展到,
而不是。
将逗号放在开头,并添加某种类型的第一个元素,无论它是否相关。一种可能性:
template<template<typename...> class Tmpl, typename... Ts>
using specialization = Tmpl<Ts...>;
using my_variant = specialization<std::variant
#define MAKE_VARIANT(name) ,name
LIST_OF_TYPES(MAKE_VARIANT)
#undef MAKE_VARIANT
>;