/
is_call_possible.hpp
245 lines (233 loc) · 23.5 KB
/
is_call_possible.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
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
#pragma once
// inspired by Roman Perepelitsa's presentation from comp.lang.c++.moderated
// based on the implementation here: http://www.rsdn.ru/forum/cpp/2759773.1.aspx
namespace is_call_possible_detail
{
template<typename T>
struct add_reference
{
typedef T& type;
};
template<typename T>
struct add_reference<T&>
{
typedef T& type;
};
} // end is_call_possible_detail
#define DEFINE_HAS_MEMBER_FUNCTION(trait_name, member_function_name) \
template<typename T, typename Signature> class trait_name; \
\
template<typename T, typename Result> \
class trait_name<T, Result(void)> \
{ \
class yes { char m; }; \
class no { yes m[2]; }; \
struct base_mixin \
{ \
Result member_function_name(); \
}; \
struct base : public T, public base_mixin {}; \
template <typename U, U t> class helper{}; \
template <typename U> \
static no deduce(U*, helper<Result (base_mixin::*)(), &U::member_function_name>* = 0); \
static yes deduce(...); \
public: \
static const bool value = sizeof(yes) == sizeof(deduce(static_cast<base*>(0))); \
}; \
\
template<typename T, typename Result, typename Arg> \
class trait_name<T, Result(Arg)> \
{ \
class yes { char m; }; \
class no { yes m[2]; }; \
struct base_mixin \
{ \
Result member_function_name(Arg); \
}; \
struct base : public T, public base_mixin {}; \
template <typename U, U t> class helper{}; \
template <typename U> \
static no deduce(U*, helper<Result (base_mixin::*)(Arg), &U::member_function_name>* = 0); \
static yes deduce(...); \
public: \
static const bool value = sizeof(yes) == sizeof(deduce(static_cast<base*>(0))); \
}; \
\
template<typename T, typename Result, typename Arg1, typename Arg2> \
class trait_name<T, Result(Arg1,Arg2)> \
{ \
class yes { char m; }; \
class no { yes m[2]; }; \
struct base_mixin \
{ \
Result member_function_name(Arg1,Arg2); \
}; \
struct base : public T, public base_mixin {}; \
template <typename U, U t> class helper{}; \
template <typename U> \
static no deduce(U*, helper<Result (base_mixin::*)(Arg1,Arg2), &U::member_function_name>* = 0); \
static yes deduce(...); \
public: \
static const bool value = sizeof(yes) == sizeof(deduce(static_cast<base*>(0))); \
}; \
\
template<typename T, typename Result, typename Arg1, typename Arg2, typename Arg3> \
class trait_name<T, Result(Arg1,Arg2,Arg3)> \
{ \
class yes { char m; }; \
class no { yes m[2]; }; \
struct base_mixin \
{ \
Result member_function_name(Arg1,Arg2,Arg3); \
}; \
struct base : public T, public base_mixin {}; \
template <typename U, U t> class helper{}; \
template <typename U> \
static no deduce(U*, helper<Result (base_mixin::*)(Arg1,Arg2,Arg3), &U::member_function_name>* = 0); \
static yes deduce(...); \
public: \
static const bool value = sizeof(yes) == sizeof(deduce(static_cast<base*>(0))); \
}; \
\
template<typename T, typename Result, typename Arg1, typename Arg2, typename Arg3, typename Arg4> \
class trait_name<T, Result(Arg1,Arg2,Arg3,Arg4)> \
{ \
class yes { char m; }; \
class no { yes m[2]; }; \
struct base_mixin \
{ \
Result member_function_name(Arg1,Arg2,Arg3,Arg4); \
}; \
struct base : public T, public base_mixin {}; \
template <typename U, U t> class helper{}; \
template <typename U> \
static no deduce(U*, helper<Result (base_mixin::*)(Arg1,Arg2,Arg3,Arg4), &U::member_function_name>* = 0); \
static yes deduce(...); \
public: \
static const bool value = sizeof(yes) == sizeof(deduce(static_cast<base*>(0))); \
};
namespace is_call_possible_detail
{
template <typename T> class void_exp_result {};
template <typename T, typename U>
U const& operator,(U const&, void_exp_result<T>);
template <typename T, typename U>
U& operator,(U&, void_exp_result<T>);
template <typename src_type, typename dest_type>
struct clone_constness
{
typedef dest_type type;
};
template <typename src_type, typename dest_type>
struct clone_constness<const src_type, dest_type>
{
typedef const dest_type type;
};
}
#define DEFINE_IS_CALL_POSSIBLE(trait_name, member_function_name) \
namespace trait_name##_detail \
{ \
DEFINE_HAS_MEMBER_FUNCTION(has_member, member_function_name) \
} \
\
template <typename T, typename Signature> \
struct trait_name \
{ \
private: \
class yes {}; \
class no { yes m[2]; }; \
struct derived : public T \
{ \
using T::member_function_name; \
no member_function_name(...) const; \
}; \
\
typedef typename is_call_possible_detail::clone_constness<T, derived>::type derived_type; \
\
template <typename U, typename Result> \
struct return_value_check \
{ \
static yes deduce(Result); \
static no deduce(...); \
static no deduce(no); \
static no deduce(is_call_possible_detail::void_exp_result<T>); \
}; \
\
template <typename U> \
struct return_value_check<U, void> \
{ \
static yes deduce(...); \
static no deduce(no); \
}; \
\
template <bool has_the_member_of_interest, typename F> \
struct impl \
{ \
static const bool value = false; \
}; \
\
template <typename Result, typename Arg> \
struct impl<true, Result(Arg)> \
{ \
static typename is_call_possible_detail::add_reference<derived_type>::type test_me; \
static typename is_call_possible_detail::add_reference<Arg>::type arg; \
\
static const bool value = \
sizeof( \
return_value_check<T, Result>::deduce( \
(test_me.member_function_name(arg), is_call_possible_detail::void_exp_result<T>()) \
) \
) == sizeof(yes); \
}; \
\
template <typename Result, typename Arg1, typename Arg2> \
struct impl<true, Result(Arg1,Arg2)> \
{ \
static typename is_call_possible_detail::add_reference<derived_type>::type test_me; \
static typename is_call_possible_detail::add_reference<Arg1>::type arg1; \
static typename is_call_possible_detail::add_reference<Arg2>::type arg2; \
\
static const bool value = \
sizeof( \
return_value_check<T, Result>::deduce( \
(test_me.member_function_name(arg1,arg2), is_call_possible_detail::void_exp_result<T>()) \
) \
) == sizeof(yes); \
}; \
\
template <typename Result, typename Arg1, typename Arg2, typename Arg3> \
struct impl<true, Result(Arg1,Arg2,Arg3)> \
{ \
static typename is_call_possible_detail::add_reference<derived_type>::type test_me; \
static typename is_call_possible_detail::add_reference<Arg1>::type arg1; \
static typename is_call_possible_detail::add_reference<Arg2>::type arg2; \
static typename is_call_possible_detail::add_reference<Arg3>::type arg3; \
\
static const bool value = \
sizeof( \
return_value_check<T, Result>::deduce( \
(test_me.member_function_name(arg1,arg2,arg3), is_call_possible_detail::void_exp_result<T>()) \
) \
) == sizeof(yes); \
}; \
\
template <typename Result, typename Arg1, typename Arg2, typename Arg3, typename Arg4> \
struct impl<true, Result(Arg1,Arg2,Arg3,Arg4)> \
{ \
static typename is_call_possible_detail::add_reference<derived_type>::type test_me; \
static typename is_call_possible_detail::add_reference<Arg1>::type arg1; \
static typename is_call_possible_detail::add_reference<Arg2>::type arg2; \
static typename is_call_possible_detail::add_reference<Arg3>::type arg3; \
static typename is_call_possible_detail::add_reference<Arg4>::type arg4; \
\
static const bool value = \
sizeof( \
return_value_check<T, Result>::deduce( \
(test_me.member_function_name(arg1,arg2,arg3,arg4), is_call_possible_detail::void_exp_result<T>()) \
) \
) == sizeof(yes); \
}; \
\
public: \
static const bool value = impl<trait_name##_detail::has_member<T,Signature>::value, Signature>::value; \
};