Created
July 5, 2020 09:31
-
-
Save g3rrit/03623db53dbd97cb22e80bac27c2a88d to your computer and use it in GitHub Desktop.
Unconventianal variant implementation. Better use std::variant.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #include <memory> | |
| #include <iostream> | |
| #include <type_traits> | |
| #include <utility> | |
| #include <tuple> | |
| #include <type_traits> | |
| #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 <class... Args> \ | |
| static inline _THIS crt_ ## cons (Args&&... args) { \ | |
| return _THIS { \ | |
| ._type = cons ## _tag, \ | |
| .cons ## _var = cons { args... } \ | |
| }; \ | |
| } \ | |
| template <class... Args> \ | |
| 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 <class T, class F> \ | |
| 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<class... Ts> struct overload : Ts... { using Ts::operator()...; }; | |
| template<class... Ts> overload(Ts...) -> overload<Ts...>; | |
| 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<int>(overload { | |
| [] (const A::B& b) { return *std::get<0>(b); }, | |
| [] (const A::C& c) { return std::get<0>(c); } | |
| }) << std::endl; | |
| return 0; | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment