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

Is it possible to use X-Macro with std::variant (or with template in general)?

提问人:auzn 提问时间:10/21/2022 更新时间:10/21/2022 访问量:153

问:

我希望使用带有 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
>
C++ C 预处理器 X-宏

评论


答:

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()IDENTITY2Type1, Type2, Type3


或者,使用我自己的宏循环库

run on 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>

稍微冗长一些,但在我的口味中更具可读性。

这里,为每个元素调用,作为元素,最初设置为(第 4 个参数)。在第一次(以及任何后续)迭代之后,被重新分配给 (aka ),因此从第二次迭代开始扩展到 而不是 。#define MAKE_VARIANT_BODY(n, d, x) d() xxdEMPTYSF_FOR_EACH()dUSE_COMMA(...)COMMAd(),

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
>;