Skip to content

Instantly share code, notes, and snippets.

@g3rrit
Created July 5, 2020 09:31
Show Gist options
  • Save g3rrit/03623db53dbd97cb22e80bac27c2a88d to your computer and use it in GitHub Desktop.
Save g3rrit/03623db53dbd97cb22e80bac27c2a88d to your computer and use it in GitHub Desktop.
Unconventianal variant implementation. Better use std::variant.
#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