using some templates with some hacky macros to allow matching on the contents of a std::variant, and getting the underlying value immediately.
also ignores if we match() on unique_ptr/shared_ptr/stack variable, match() works the same.
using some templates with some hacky macros to allow matching on the contents of a std::variant, and getting the underlying value immediately.
also ignores if we match() on unique_ptr/shared_ptr/stack variable, match() works the same.
#include <matching-variant.hpp> | |
struct Add; struct Sub;struct Mul;struct Div; struct Var;struct Func; | |
using ASTNode = std::variant<Add, Sub, Mul, Div, Var, Func>; | |
struct Add{ std::unique_ptr<ASTNode> lhs; std::unique_ptr<ASTNode> rhs;}; | |
struct Sub{ int lhs, rhs;}; | |
struct Mul{int lhs;}; | |
struct Div{}; | |
struct Var{}; | |
struct Func{}; | |
int main() { | |
ASTNode v = Add { | |
.lhs = std::make_unique<ASTNode>(Sub {1, 2}), | |
.rhs = std::make_unique<ASTNode>(Sub {2, 4}), | |
}; | |
match(v) { | |
holds(Add, &add_var) { | |
match(add_var.lhs) { | |
holds(Mul, mul) { | |
std::cout << "mul was: " << mul.lhs << '\n'; | |
} | |
holds(Sub, sub) std::cout << "inner was sub: "<< sub.lhs; | |
_ {} | |
} | |
} | |
holds(Sub, sub) std::cout << "was sub"; | |
holds(Mul, mul) std::cout << "was mul.\n"; | |
_ std::cerr << "type unknown.\n"; | |
} | |
} | |
#include <iostream> | |
#include <memory> | |
#include <type_traits> | |
#include <variant> | |
template<typename T, typename Head, typename... Tail> | |
constexpr int type_index(int index = 0) { | |
if constexpr (std::is_same_v<T, Head>) return index; | |
else | |
return type_index<T, Tail...>(index + 1); | |
} | |
template<typename... Types> | |
struct type_sequence { | |
constexpr type_sequence(const std::variant<Types...>&) {} | |
constexpr type_sequence(std::unique_ptr<std::variant<Types...>>&) {} | |
constexpr type_sequence(std::shared_ptr<std::variant<Types...>>&) {} | |
template<typename T> | |
constexpr static int idx = type_index<T, Types...>(); | |
}; | |
template<typename ...Types> inline size_t index_of(std::shared_ptr<std::variant<Types...>>& node) { return node->index(); } | |
template<typename ...Types> inline size_t index_of(std::unique_ptr<std::variant<Types...>>& node) { return node->index(); } | |
template<typename ...Types> inline size_t index_of(std::variant<Types...>& node) { return node.index(); } | |
template<typename T, typename ...Types> auto& get_elem(std::unique_ptr<std::variant<Types...>>& node) { return std::get<T>(*node); } | |
template<typename T, typename ...Types> auto& get_elem(std::shared_ptr<std::variant<Types...>>& node) { return std::get<T>(*node); } | |
template<typename T, typename ...Types> auto& get_elem(std::variant<Types...>& node) { return std::get<T>(node); } | |
#define match(v) \ | |
{ \ | |
auto& fumo__v__ = v; \ | |
bool was_default = false; \ | |
switch (auto fumo__t_seq__ = type_sequence(v); index_of(v)) { | |
#define holds(T, name) \ | |
break;} \ | |
case fumo__t_seq__.idx<std::remove_pointer<std ::remove_cvref<T>::type>::type>: { \ | |
T name = get_elem<std::remove_pointer<std ::remove_cvref<T>::type>::type>(fumo__v__); | |
#define _ \ | |
break; \ | |
} \ | |
default: \ | |
was_default = true; \ | |
} \ | |
if (was_default) | |