I hope to do the following using X-macro with c++17, but since template parameter does not support trailing comma, it does not work for the std::variant part. Is there someway around it?
#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
>
Yes, there's a workaround:
#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
>
Without IDENTITY2(...)
this expands to EMPTY(,) Type1 IDENTITY(,) Type2 IDENTITY(,) Type3 IDENTITY()
. IDENTITY2
forces it to expand again, this time to Type1, Type2, Type3
.
Or, with my own macro looping library:
#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>
Slightly more verbose, but more readable in my taste.
Here, #define MAKE_VARIANT_BODY(n, d, x) d() x
is called for each element, with x
being the element, and d
initially set to EMPTY
(4th argument of SF_FOR_EACH()
). After the first (and any subsequent) iteration, d
is reassigned to USE_COMMA(...)
(aka COMMA
), so starting from the second iteration d()
expands to ,
instead of
.