"ScL Feature"/
ScL Feature 0.0.1
C++20 composable proxy wrapper with pluggable executor strategy
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__>()