是否可以将X-Macro与std::variant一起使用(或与模板一起使用)



我希望在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
>;

相关内容

  • 没有找到相关文章

最新更新