#include #include #include #include #include #include #define MAKE_ENUM_VAR(cons, ...) \ cons ## _tag, #define MAKE_ENUM(LIST) \ enum { \ LIST(MAKE_ENUM_VAR) \ } _type; #define MAKE_UNION_DECL_VAR(cons, ...) \ struct cons : public std::tuple < __VA_ARGS__ > { \ using std::tuple< __VA_ARGS__ >::tuple; \ }; #define MAKE_UNION_VAR(cons, ...) \ cons cons ## _var; #define MAKE_UNION(LIST) \ LIST(MAKE_UNION_DECL_VAR) \ union { \ LIST(MAKE_UNION_VAR) \ }; #define MAKE_CONSTRUCTOR_VAR(cons, ...) \ template \ static inline _THIS crt_ ## cons (Args&&... args) { \ return _THIS { \ ._type = cons ## _tag, \ .cons ## _var = cons { args... } \ }; \ } \ template \ static inline _THIS* new_ ## cons (Args&&... args) { \ return new _THIS { \ ._type = cons ## _tag, \ .cons ## _var = cons { args... } \ }; \ } #define MAKE_CONSTRUCTOR(LIST) \ LIST(MAKE_CONSTRUCTOR_VAR) #define MAKE_VISIT_VAR(cons, ...) \ case cons ## _tag: { \ return _visit_f(cons ## _var); \ } #define MAKE_VISIT(LIST) \ template \ T visit(F _visit_f) { \ switch (_type) { \ LIST(MAKE_VISIT_VAR) \ } \ return *(T*)nullptr; \ } #define MAKE_GET_VAR(cons, ...) \ cons get_ ## cons() { \ if (_type != cons ## _tag) { \ throw std::runtime_error("Variant tag does not match"); \ } \ return cons ## _var; \ } #define MAKE_GET(LIST) \ LIST(MAKE_GET_VAR) #define MAKE_VARIANT(TYPE, LIST) \ using _THIS = TYPE; \ MAKE_ENUM(LIST) \ MAKE_UNION(LIST) \ MAKE_CONSTRUCTOR(LIST) \ MAKE_VISIT(LIST) \ MAKE_GET(A_LIST) template struct overload : Ts... { using Ts::operator()...; }; template overload(Ts...) -> overload; struct A { #define A_LIST(X) \ X(B, int*, float) \ X(C, int) MAKE_VARIANT(A, A_LIST) }; int main() { A r = A::crt_B(new int(10), 1.3); std::cout << r.visit(overload { [] (const A::B& b) { return *std::get<0>(b); }, [] (const A::C& c) { return std::get<0>(c); } }) << std::endl; return 0; }