"ScL Feature"
/
ScL Feature
0.0.1
C++20 composable proxy wrapper with pluggable executor strategy
Toggle main menu visibility
Loading...
Searching...
No Matches
has_qualified_method.h
Go to the documentation of this file.
1
#pragma once
2
6
7
#include <scl/utility/preprocessor/forward.h>
8
9
#include <type_traits>
10
17
#define SCL_HQM_CALL(method, quals) \
18
::std::declval<Obj quals>().method(::std::declval<ScLCallArgs>()...)
19
26
#define SCL_HQM_SAME(method, left_quals, right_quals) \
27
::std::is_same_v<decltype(SCL_HQM_CALL(SCL_FORWARD(method), left_quals)), \
28
decltype(SCL_HQM_CALL(SCL_FORWARD(method), right_quals))>
29
126
127
#define SCL_HAS_QUALIFIED_METHOD(method, Type, ...) \
128
([]<typename ScLObjType, typename... ScLCallArgs>() -> bool { \
129
using Obj = ::std::remove_cvref_t<ScLObjType>; \
130
using Base = ::std::remove_reference_t<ScLObjType>; \
131
\
132
constexpr bool is_obj_rvalue = ::std::is_rvalue_reference_v<ScLObjType>; \
133
constexpr bool is_obj_lvalue = ::std::is_lvalue_reference_v<ScLObjType>; \
134
constexpr bool is_obj_const = ::std::is_const_v<Base>; \
135
constexpr bool is_obj_volatile = ::std::is_volatile_v<Base>; \
136
constexpr bool is_obj_cv = is_obj_const && is_obj_volatile; \
137
\
138
/* --- lvalue callability --- */
\
139
constexpr bool can_lv_m = requires { SCL_HQM_CALL(SCL_FORWARD(method), &); }; \
140
constexpr bool can_lv_c = requires { SCL_HQM_CALL(SCL_FORWARD(method), const &); }; \
141
constexpr bool can_lv_v = requires { SCL_HQM_CALL(SCL_FORWARD(method), volatile &); }; \
142
constexpr bool can_lv_cv = requires { SCL_HQM_CALL(SCL_FORWARD(method), const volatile &); }; \
143
\
144
/* --- rvalue callability --- */
\
145
constexpr bool can_rv_m = requires { SCL_HQM_CALL(SCL_FORWARD(method), &&); }; \
146
constexpr bool can_rv_c = requires { SCL_HQM_CALL(SCL_FORWARD(method), const &&); }; \
147
constexpr bool can_rv_v = requires { SCL_HQM_CALL(SCL_FORWARD(method), volatile &&); }; \
148
constexpr bool can_rv_cv = requires { SCL_HQM_CALL(SCL_FORWARD(method), const volatile &&); }; \
149
\
150
/* --- lvalue qualifier detection --- */
\
151
/* Return-type comparisons (SCL_HQM_SAME) are guarded by if-constexpr */
\
152
/* callability checks so that decltype is never evaluated on an ill-formed call. */
\
153
if constexpr (is_obj_lvalue) \
154
{ \
155
if constexpr (is_obj_cv) \
156
{ \
157
return can_lv_cv; \
158
} \
159
else if constexpr (is_obj_volatile || is_obj_const) \
160
{ \
161
constexpr bool can_narrow = is_obj_volatile ? can_lv_v : can_lv_c; \
162
constexpr bool can_wider = can_lv_cv; \
163
if constexpr (!can_narrow) \
164
return false; \
165
else if constexpr (!can_wider) \
166
return true; \
167
else \
168
return !(is_obj_volatile \
169
? SCL_HQM_SAME(SCL_FORWARD(method), volatile &, const volatile &) \
170
: SCL_HQM_SAME(SCL_FORWARD(method), const &, const volatile &)); \
171
} \
172
else \
173
{ \
174
/* mutable lvalue: must differ from every wider qualifier that is callable. */
\
175
if constexpr (!can_lv_m) \
176
return false; \
177
else \
178
{ \
179
if constexpr (can_lv_c) \
180
{ \
181
if constexpr (SCL_HQM_SAME(SCL_FORWARD(method), &, const &)) \
182
return false; \
183
} \
184
if constexpr (can_lv_v) \
185
{ \
186
if constexpr (SCL_HQM_SAME(SCL_FORWARD(method), &, volatile &)) \
187
return false; \
188
} \
189
if constexpr (can_lv_cv) \
190
{ \
191
if constexpr (SCL_HQM_SAME(SCL_FORWARD(method), &, const volatile &)) \
192
return false; \
193
} \
194
return true; \
195
} \
196
} \
197
} \
198
/* --- rvalue qualifier detection --- */
\
199
else if constexpr (is_obj_rvalue) \
200
{ \
201
if constexpr (is_obj_cv) \
202
{ \
203
return can_rv_cv; \
204
} \
205
else if constexpr (is_obj_volatile) \
206
{ \
207
if constexpr (!can_rv_v) \
208
return false; \
209
else if constexpr (!can_rv_cv) \
210
return true; \
211
else \
212
return !SCL_HQM_SAME(SCL_FORWARD(method), volatile &&, const volatile &&); \
213
} \
214
else if constexpr (is_obj_const) \
215
{ \
216
/* MSVC cross-category check: const& is callable on rvalues (non-standard). */
\
217
/* Detect implicit binding by comparing return types across categories. */
\
218
if constexpr (!can_rv_c) \
219
return false; \
220
else \
221
{ \
222
if constexpr (can_rv_cv) \
223
{ \
224
if constexpr (SCL_HQM_SAME(SCL_FORWARD(method), const &&, const volatile &&)) \
225
return false; \
226
} \
227
if constexpr (can_lv_c) \
228
{ \
229
if constexpr (SCL_HQM_SAME(SCL_FORWARD(method), const &&, const &)) \
230
{ \
231
if constexpr (!can_rv_m) \
232
return false; \
233
else \
234
{ \
235
constexpr bool scl_same_rv = SCL_HQM_SAME(SCL_FORWARD(method), &&, const &&); \
236
if constexpr (scl_same_rv) \
237
return false; \
238
} \
239
} \
240
} \
241
return true; \
242
} \
243
} \
244
else \
245
{ \
246
/* mutable rvalue: must differ from every wider qualifier that is callable. */
\
247
if constexpr (!can_rv_m) \
248
return false; \
249
else \
250
{ \
251
if constexpr (can_rv_c) \
252
{ \
253
if constexpr (SCL_HQM_SAME(SCL_FORWARD(method), &&, const &&)) \
254
return false; \
255
} \
256
if constexpr (can_rv_v) \
257
{ \
258
if constexpr (SCL_HQM_SAME(SCL_FORWARD(method), &&, volatile &&)) \
259
return false; \
260
} \
261
if constexpr (can_rv_cv) \
262
{ \
263
if constexpr (SCL_HQM_SAME(SCL_FORWARD(method), &&, const volatile &&)) \
264
return false; \
265
} \
266
return true; \
267
} \
268
} \
269
} \
270
else \
271
{ \
272
return false; \
273
} \
274
}).template operator()<SCL_FORWARD(Type), ##__VA_ARGS__>()
src
scl
feature
type_traits
has_qualified_method.h
Generated by
1.18.0