ugmisc 0.2
Miscellaneous C++ header library
Loading...
Searching...
No Matches
member.hpp
Go to the documentation of this file.
1/*
2 * SPDX-Licence-Identifier: MIT
3 *
4 * Copyright 2025 Larry Chips
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the “Software”), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 * SOFTWARE.
23 */
24#pragma once
25
41
42#include "ugmisc/typelist.hpp"
43#include <utility>
44
45
46
47
48#ifdef UGMISC_DOCS
49#error
50#endif
51
52
53
54
55namespace ugmisc {
56
57
58
59
60#ifdef UGMISC_DOCS
61
69template<class...T>
76 template<class...U>
77 static constexpr decltype(auto) call(U&&...args);
78
79
90 template<class...U>
91 constexpr decltype(auto) operator() (U&&...) const;
92
93
120 template<class F>
121 static constexpr auto fallback(
122 F&& functor
123 );
124
125
131 template<class...U>
132 using matched_type = ???;
133
138 template<class...U>
139 static constexpr bool is_matched_v = ???;
140
141
145 template<class...U>
146 static constexpr bool is_matched(U&&...);
147
148
155 template<class...U>
156 static matched_type<U...> declval_matched(U&&...) noexcept;
157};
158
159#endif /* UGMISC_DOCS */
160
161
163namespace member_ {
164
165
166
167
182template<class StaticCaller, class Functor>
183class fallback_caller {
184 Functor m_functor;
185
186 /*
187 * The use of Dummy* for the first override and Dummy for the second, makes
188 * the first more specific.
189 */
190 template<class Dummy, class...T>
191 constexpr auto forward(Dummy*, T&&...args) const
192 -> decltype(m_functor(std::forward<T>(args)...))
193 {
194 return m_functor(std::forward<T>(args)...);
195 }
196
197 template<class Dummy, class...T>
198 constexpr decltype(auto) forward(Dummy, T&&...args) const {
199 return m_functor();
200 }
201
202
203public:
204 constexpr fallback_caller(const Functor& f) : m_functor(f) {}
205 constexpr fallback_caller(Functor&& f) : m_functor(std::move(f)) {}
206
207 fallback_caller(fallback_caller&&) = default;
208 fallback_caller(const fallback_caller&) = delete;
209
210 template<class...T>
211 constexpr decltype(auto) call(T&&...args) const {
212 if constexpr ( StaticCaller::template is_matched_v<T...> ) {
213 return StaticCaller::call(std::forward<T>(args)...);
214 } else {
215 auto dummy = (int*)nullptr;
216 return forward(dummy, std::forward<T>(args)...);
217 }
218 }
219
220 template<class...T>
221 constexpr decltype(auto) operator()(T&&...args) const {
222 return call(std::forward<T>(args)...);
223 }
224};
225
226
227
228
229
230} /* member_ (::ugmisc::member_) */
231
232
234
235} /* ::ugmisc */
236
237
238
239
280#define UGMISC_NAMED_MEMBER_TYPE_TEST(TEMPLATENAME, ALIASNAME, HASMEMBERNAME, NAME) template<class TYPE, class DEFAULTTYPE = void> \
281 class TEMPLATENAME { \
282 template<class...> struct get_defined_type; \
283 \
284 template<class V, class T, class...Ts> struct get_defined_type<V, T, Ts...> { \
285 static constexpr bool has_member = get_defined_type<void, Ts...>::has_member; \
286 using type = typename get_defined_type<void, Ts...>::type; \
287 }; \
288 \
289 template<class T, class...Ts> struct get_defined_type<std::void_t<typename T::NAME>, T, Ts...> { \
290 static constexpr bool has_member = true; \
291 using type = typename T::NAME; \
292 }; \
293 \
294 template<class V> struct get_defined_type<V> { \
295 static constexpr bool has_member = false; \
296 using type = DEFAULTTYPE; \
297 }; \
298 \
299 using tlist = ::ugmisc::flatten_t<void, TYPE>; \
300 using dt = typename tlist::template apply<get_defined_type>; \
301 \
302 public: \
303 using type = typename dt::type; \
304 static constexpr bool has_member = dt::has_member; \
305 }; \
306 \
307 template<class T, class D=void> \
308 using ALIASNAME = typename TEMPLATENAME<T, D>::type; \
309 \
310 template<class...T> \
311 static constexpr bool HASMEMBERNAME = TEMPLATENAME<::ugmisc::type_list<T...>>::has_member
312
313
314
315
343#define UGMISC_MEMBER_TYPE_TEST(NAME) \
344 UGMISC_NAMED_MEMBER_TYPE_TEST(member_type_test_##NAME, member_type_##NAME, has_member_type_##NAME, NAME)
345
346
347
349
350#define UGMISC__MEMBER_CALLER_TYPE_NAME(TNAME) _ugmisc_caller_##TNAME
351
360#define UGMISC__DECL_MEMBER_CALLER_TYPE(TNAME, NAME) \
361struct UGMISC__MEMBER_CALLER_TYPE_NAME(TNAME) { \
362 \
363 template<class T, class, class...A> \
364 struct caller { \
365 static constexpr bool is_callable = false; \
366 }; \
367 \
368 template<class T, class...A> \
369 struct caller<T, std::void_t<decltype(T::NAME(std::declval<A>()...))>, A...> { \
370 static constexpr bool is_callable = true; \
371 \
372 static constexpr decltype(auto) call(A...args) { \
373 return T::NAME(std::forward<A>(args)...); \
374 } \
375 }; \
376}
377
378namespace ugmisc {
379namespace member_ {
380
381
382template<class Caller, class T, class...A>
383inline constexpr bool is_callable_v =
384 Caller::template caller<T, void, A...>::is_callable;
385
386
387template<class Caller, class T, class...A>
388constexpr bool is_callable(A&&...) {
389 return is_callable_v<Caller, T, A...>;
390}
391
392
393
394
399template<class Caller, class...T>
400class chain_caller {
401 template<class V, class List, class...Args>
402 struct caller
403 : public caller<V, type_list_remove_prefix<1, List>, Args...> {
404 };
405
406 template<class...Args> struct caller<void, type_list<>, Args...> {
407 static constexpr bool is_callable = false;
408 };
409
410 template<class List, class...Args>
411 struct caller<
412 std::enable_if_t< is_callable_v<Caller, type_list_member<0, List>, Args...>>,
413 List,
414 Args...
415 >
416 {
417 static constexpr bool is_callable = true;
418 using type = type_list_member<0, List>;
419 };
420
421 using types_list = flatten_t<T...>;
422
423public:
424 template<class...Args>
425 static constexpr bool is_matched_v =
426 caller<void, types_list, Args...>::is_callable;
427
428 template<class...Args>
429 static constexpr bool is_matched(Args&&...) {
430 return is_matched_v<Args...>;
431 }
432
433 template<class...Args>
434 using matched_type = typename caller<void, types_list, Args...>::type;
435
436 template<class...Args>
437 static constexpr decltype(auto) call(Args&&...args) {
438 static_assert(
439 is_matched_v<Args...>,
440 "None of the types is callable with these argument types."
441 );
442 return Caller::template caller<matched_type<Args...>, void, Args...>
443 ::call(std::forward<Args>(args)...);
444 }
445
446 template<class...Args>
447 constexpr decltype(auto) operator()(Args&&...args) const {
448 return call(std::forward<Args>(args)...);
449 }
450
451 template<class F>
452 static constexpr
453 fallback_caller<chain_caller, std::remove_reference_t<F>>
454 fallback(F&& functor) {
455 return std::forward<F>(functor);
456 }
457
458 template<class...Args>
459 static matched_type<Args...> declval_matched(Args&&...) noexcept;
460};
461
462
463} }
464
465
467
468
469
470
509#define UGMISC_NAMED_MEMBER_STATIC_METHOD_CALL(TEMPLATENAME, NAME) \
510 UGMISC__DECL_MEMBER_CALLER_TYPE(TEMPLATENAME, NAME); \
511 template<class...T> class TEMPLATENAME \
512 : public ::ugmisc::member_::chain_caller< \
513 UGMISC__MEMBER_CALLER_TYPE_NAME(TEMPLATENAME), \
514 T... \
515 > \
516 { \
517 static constexpr const char *template_name = #TEMPLATENAME; \
518 static constexpr const char *function_name = #NAME; \
519 }
520
521
529#define UGMISC_MEMBER_STATIC_METHOD_CALL(NAME) \
530 UGMISC_NAMED_MEMBER_STATIC_METHOD_CALL(member_call_##NAME, NAME)
Definition member.hpp:70
static constexpr decltype(auto) call(U &&...args)
static constexpr auto fallback(F &&functor)
??? matched_type
Definition member.hpp:132
static matched_type< U... > declval_matched(U &&...) noexcept
static constexpr bool is_matched(U &&...)
static constexpr bool is_matched_v
Definition member.hpp:139
Lists of types which may be used in some of the ugmisc templates where a single type would usually be...