提问人:auzn 提问时间:10/21/2022 更新时间:10/21/2022 访问量:153
是否可以将 X-Macro 与 std::variant(或一般的模板)一起使用?
Is it possible to use X-Macro with std::variant (or with template in general)?
问:
我希望使用带有 c++17 的 X-macro 执行以下操作,但由于模板参数不支持尾随逗号,因此它不适用于 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
>
答:
2赞
HolyBlackCat
10/21/2022
#1
是的,有一种解决方法:
#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
或者,使用我自己的宏循环库:
#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>
稍微冗长一些,但在我的口味中更具可读性。
这里,为每个元素调用,作为元素,最初设置为(第 4 个参数)。在第一次(以及任何后续)迭代之后,被重新分配给 (aka ),因此从第二次迭代开始扩展到 而不是 。#define MAKE_VARIANT_BODY(n, d, x) d() x
x
d
EMPTY
SF_FOR_EACH()
d
USE_COMMA(...)
COMMA
d()
,
1赞
user17732522
10/21/2022
#2
将逗号放在开头并添加某种元素的第一个元素,无论它是否相关。一种可能性:
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
>;
评论