-
Notifications
You must be signed in to change notification settings - Fork 35
/
Copy pathcase_study_2.hpp
117 lines (89 loc) · 3.44 KB
/
case_study_2.hpp
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
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
#include <type_traits>
/* Type list */
template <typename... Args>
struct type_list;
template <typename Type>
struct type_list<Type> {
using head = Type;
};
template <typename Head, typename... Tail>
struct type_list<Head, Tail...> : type_list<Head> {
using tail = type_list<Tail...>;
};
/* OMG this awesome void_t metafunction will change your life */
template <typename...>
using void_t = void;
/* Type list metafunctions */
/* count */
template <typename T, typename = void>
struct count : std::integral_constant<int, 1> {};
template <typename T>
struct count<T, void_t<typename T::tail>> :
std::integral_constant<int, 1 + count<typename T::tail>()> {};
/* Alternate implementation uses fewer template instantiations */
template <typename... Elts>
struct different_count;
template <typename... Elts>
struct different_count<type_list<Elts...>> : std::integral_constant<int, sizeof...(Elts)> {};
/* has_tail predicate */
template <typename T>
struct has_tail : /* predicate */ /* if true */ /* if false */
std::conditional<(different_count<T>::value <= 1), std::false_type, std::true_type>::type {};
/* has_handler predicate */
template <typename Handler, typename Evt, typename = void>
struct has_handler : std::false_type {};
template <typename Handler, typename Evt>
struct has_handler<Handler, Evt, decltype( Handler::handle( std::declval<const Evt&>() ) )> :
std::true_type {};
/* Dispatcher */
template <typename Listeners>
class Dispatcher {
template <typename Evt, typename List, bool HasTail, bool HasHandler>
struct post_impl;
// Case 1: Has tail, has a handler
template <typename Evt, typename List>
struct post_impl<Evt, List, true, true>
{
static void call(const Evt& evt) {
List::head::handle(evt);
using Tail = typename List::tail;
constexpr bool has_tail_v = has_tail<Tail>::value;
constexpr bool has_handler_v = has_handler<typename Tail::head, Evt>::value;
post_impl<Evt, Tail, has_tail_v, has_handler_v>::call(evt);
}
};
// Case 2: Has no tail, has a handler
template <typename Evt, typename List>
struct post_impl<Evt, List, false, true>
{
static void call(const Evt& evt) {
List::head::handle(evt);
}
};
// Case 3: Has tail, has no handler
template <typename Evt, typename List>
struct post_impl<Evt, List, true, false>
{
static void call(const Evt& evt) {
using Tail = typename List::tail;
constexpr bool has_tail_v = has_tail<Tail>::value;
constexpr bool has_handler_v = has_handler<typename Tail::head, Evt>::value;
post_impl<Evt, Tail, has_tail_v, has_handler_v>::call(evt);
}
};
// Case 4: Has no tail, has no handler
template <typename Evt, typename List>
struct post_impl<Evt, List, false, false>
{
static void call(const Evt& evt) {
// do nothing.
}
};
public:
template <typename Evt>
static void post(const Evt& t) {
constexpr bool has_tail_v = has_tail<Listeners>::value;
constexpr bool has_handler_v = has_handler<typename Listeners::head, Evt>::value;
post_impl<Evt, Listeners, has_tail_v, has_handler_v>::call(t);
}
};