Skip to content

Instantly share code, notes, and snippets.

@g3rrit
Created July 5, 2020 09:31
Show Gist options
  • Select an option

  • Save g3rrit/03623db53dbd97cb22e80bac27c2a88d to your computer and use it in GitHub Desktop.

Select an option

Save g3rrit/03623db53dbd97cb22e80bac27c2a88d to your computer and use it in GitHub Desktop.

Revisions

  1. g3rrit created this gist Jul 5, 2020.
    103 changes: 103 additions & 0 deletions variant.hpp
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,103 @@
    #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;
    }