-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathchurch.cpp
More file actions
79 lines (52 loc) · 1.72 KB
/
church.cpp
File metadata and controls
79 lines (52 loc) · 1.72 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
// -*- compile-command: "c++ -std=c++14 church.cpp -o church" -*-
#include <memory>
template<class T=void>
using fun_ptr = void(*)();
template<class A, class ... Args>
struct selector {
template<class Derived>
friend auto make_select(const Derived*, const A&) {
return +[](fun_ptr<Args> ... ptrs) {
fun_ptr<> res = nullptr;
const int expand[] = {
(std::is_same<A, Args>::value ? (res = ptrs, 0) : 0)...};
return res;
};
};
};
template<class Visitor, class ... Args>
using visitor_result = std::common_type_t<std::result_of_t<Visitor(Args)>...>;
template<class ... Args>
class variant: selector<Args, Args...>... {
using storage_type = std::aligned_union_t<0, Args...>;
storage_type storage;
fun_ptr<> (*select)(fun_ptr<Args>...);
public:
template<class T>
variant(const T& self): select(make_select(this, self)) {}
template<class T>
const T& get() const & {
return *reinterpret_cast<const T*>(this);
}
template<class T>
T&& get() && {
return std::move(*reinterpret_cast<T*>(this));
}
template<class Self, class Visitor, class Ret=visitor_result<Visitor, Args...>>
friend Ret visit(Self&& self, const Visitor& visitor) {
using thunk_type = Ret (*)(Self&&, const Visitor& visitor);
auto thunk = self.select(fun_ptr<Args>(+[](Self&& self,
const Visitor& visitor) {
return visitor(std::forward<Self>(self).template get<Args>());
})...);
return thunk_type(thunk)(std::forward<Self>(self), visitor);
}
};
#include <iostream>
int main(int, char**) {
variant<int, double> test = 1.0;
visit(test, [](auto self) {
std::clog << typeid(self).name() << std::endl;
});
return 0;
}