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
| namespace es {
template <typename ConcreteT>
class MemberFunctionFactory {
public:
template <typename KeyT, typename RetT, typename... Args>
class FactoryType;
template <typename FactoryT>
static constexpr size_t initialize(
typename std::initializer_list<std::pair<typename FactoryT::key_type,
typename FactoryT::op_type>> init) {
for (auto p : init)
FactoryT::holder.emplace(std::move(p));
return init.size();
}
template <typename FactoryT>
static void initialize_once(
typename std::initializer_list<std::pair<typename FactoryT::key_type,
typename FactoryT::op_type>> init) {
static auto dummy = initialize<FactoryT>(std::move(init));
(void)dummy;
}
template <typename FactoryT, typename... Args>
std::optional<std::enable_if_t<!std::is_void_v<typename FactoryT::ret_type>,
typename FactoryT::ret_type>>
invoke(typename FactoryT::key_type c, Args&&... args) {
if (auto it = FactoryT::holder.find(c); it != FactoryT::holder.end()) {
return std::invoke(it->second, static_cast<ConcreteT*>(this),
std::forward<Args>(args)...);
}
return std::nullopt;
}
template <typename FactoryT, typename... Args>
std::enable_if_t<std::is_void_v<typename FactoryT::ret_type>>
invoke(typename FactoryT::key_type c, Args&&... args) {
if (auto it = FactoryT::holder.find(c); it != FactoryT::holder.end()) {
std::invoke(it->second, static_cast<ConcreteT*>(this),
std::forward<Args>(args)...);
}
}
};
template <typename ConcreteT>
template <typename KeyT, typename RetT, typename... Args>
class MemberFunctionFactory<ConcreteT>::FactoryType {
private:
friend MemberFunctionFactory<ConcreteT>;
using key_type = KeyT;
using ret_type = RetT;
using op_type = RetT (ConcreteT::*)(Args...);
using CreatorHolder = std::map<key_type, op_type>;
static CreatorHolder holder;
};
template <typename ConcreteT>
template <typename KeyT, typename RetT, typename... Args>
typename MemberFunctionFactory<ConcreteT>::template FactoryType<KeyT, RetT, Args...>::CreatorHolder
MemberFunctionFactory<ConcreteT>::template FactoryType<KeyT, RetT, Args...>::holder = {};
} // es
class OpCluster : public es::MemberFunctionFactory<OpCluster> {
using factory_type = FactoryType<char, int, int, int>;
public:
OpCluster() {
initialize_once<factory_type>({
{'+', &OpCluster::plus},
{'-', &OpCluster::minus},
{'*', &OpCluster::star},
{'/', &OpCluster::div}
});
}
int plus(int lhs, int rhs) {
return (lhs + rhs) * scale;
}
int minus(int lhs, int rhs) {
return (lhs - rhs) * scale;
}
int star(int lhs, int rhs) {
return (lhs * rhs) * scale;
}
int div(int lhs, int rhs) {
return (lhs / rhs) * scale;
}
std::optional<int> calc(char c, int lhs, int rhs) {
return invoke<factory_type>(c, lhs, rhs);
}
private:
int scale = 10;
};
|