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