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
38
39#include "ugmisc/typelist.hpp"
40#include <utility>
41
42
43
44
45#ifdef UGMISC_DOCS
46#error
47#endif
48
49
50
51
52namespace ugmisc {
53
54
55
56
57#ifdef UGMISC_DOCS
58
66template<class...T>
73 template<class...U>
74 static constexpr decltype(auto) call(U&&...args);
75
76
87 template<class...U>
88 constexpr decltype(auto) operator() (U&&...) const;
89
90
117 template<class F>
118 static constexpr auto fallback(
119 F&& functor
120 );
121
122
128 template<class...U>
129 using matched_type = ???;
130
135 template<class...U>
136 static constexpr bool is_matched_v = ???;
137
138
142 template<class...U>
143 static constexpr bool is_matched(U&&...);
144
145
152 template<class...U>
153 static matched_type<U...> declval_matched(U&&...) noexcept;
154};
155
156#endif /* UGMISC_DOCS */
157
158
160namespace member_ {
161
162
163
164
179template<class StaticCaller, class Functor>
180class fallback_caller {
181 Functor m_functor;
182
183 /*
184 * The use of Dummy* for the first override and Dummy for the second, makes
185 * the first more specific.
186 */
187 template<class Dummy, class...T>
188 constexpr auto forward(Dummy*, T&&...args) const
189 -> decltype(m_functor(std::forward<T>(args)...))
190 {
191 return m_functor(std::forward<T>(args)...);
192 }
193
194 template<class Dummy, class...T>
195 constexpr decltype(auto) forward(Dummy, T&&...args) const {
196 return m_functor();
197 }
198
199
200public:
201 constexpr fallback_caller(const Functor& f) : m_functor(f) {}
202 constexpr fallback_caller(Functor&& f) : m_functor(std::move(f)) {}
203
204 fallback_caller(fallback_caller&&) = default;
205 fallback_caller(const fallback_caller&) = delete;
206
207 template<class...T>
208 constexpr decltype(auto) call(T&&...args) const {
209 if constexpr ( StaticCaller::template is_matched_v<T...> ) {
210 return StaticCaller::call(std::forward<T>(args)...);
211 } else {
212 auto dummy = (int*)nullptr;
213 return forward(dummy, std::forward<T>(args)...);
214 }
215 }
216
217 template<class...T>
218 constexpr decltype(auto) operator()(T&&...args) const {
219 return call(std::forward<T>(args)...);
220 }
221};
222
223
224
225
226
227} /* member_ (::ugmisc::member_) */
228
229
231
232} /* ::ugmisc */
233
234
235
236
277#define UGMISC_NAMED_MEMBER_TYPE_TEST(TEMPLATENAME, ALIASNAME, HASMEMBERNAME, NAME) template<class TYPE, class DEFAULTTYPE = void> \
278 class TEMPLATENAME { \
279 template<class...> struct get_defined_type; \
280 \
281 template<class V, class T, class...Ts> struct get_defined_type<V, T, Ts...> { \
282 static constexpr bool has_member = get_defined_type<void, Ts...>::has_member; \
283 using type = typename get_defined_type<void, Ts...>::type; \
284 }; \
285 \
286 template<class T, class...Ts> struct get_defined_type<std::void_t<typename T::NAME>, T, Ts...> { \
287 static constexpr bool has_member = true; \
288 using type = typename T::NAME; \
289 }; \
290 \
291 template<class V> struct get_defined_type<V> { \
292 static constexpr bool has_member = false; \
293 using type = DEFAULTTYPE; \
294 }; \
295 \
296 using tlist = ::ugmisc::flatten_t<void, TYPE>; \
297 using dt = typename tlist::template apply<get_defined_type>; \
298 \
299 public: \
300 using type = typename dt::type; \
301 static constexpr bool has_member = dt::has_member; \
302 }; \
303 \
304 template<class T, class D=void> \
305 using ALIASNAME = typename TEMPLATENAME<T, D>::type; \
306 \
307 template<class...T> \
308 static constexpr bool HASMEMBERNAME = TEMPLATENAME<::ugmisc::type_list<T...>>::has_member
309
310
311
312
340#define UGMISC_MEMBER_TYPE_TEST(NAME) \
341 UGMISC_NAMED_MEMBER_TYPE_TEST(member_type_test_##NAME, member_type_##NAME, has_member_type_##NAME, NAME)
342
343
344
346
347#define UGMISC__MEMBER_CALLER_TYPE_NAME(TNAME) _ugmisc_caller_##TNAME
348
357#define UGMISC__DECL_MEMBER_CALLER_TYPE(TNAME, NAME) \
358struct UGMISC__MEMBER_CALLER_TYPE_NAME(TNAME) { \
359 \
360 template<class T, class, class...A> \
361 struct caller { \
362 static constexpr bool is_callable = false; \
363 }; \
364 \
365 template<class T, class...A> \
366 struct caller<T, std::void_t<decltype(T::NAME(std::declval<A>()...))>, A...> { \
367 static constexpr bool is_callable = true; \
368 \
369 static constexpr decltype(auto) call(A...args) { \
370 return T::NAME(std::forward<A>(args)...); \
371 } \
372 }; \
373}
374
375namespace ugmisc {
376namespace member_ {
377
378
379template<class Caller, class T, class...A>
380inline constexpr bool is_callable_v =
381 Caller::template caller<T, void, A...>::is_callable;
382
383
384template<class Caller, class T, class...A>
385constexpr bool is_callable(A&&...) {
386 return is_callable_v<Caller, T, A...>;
387}
388
389
390
391
396template<class Caller, class...T>
397class chain_caller {
398 template<class V, class List, class...Args>
399 struct caller
400 : public caller<V, type_list_remove_prefix<1, List>, Args...> {
401 };
402
403 template<class...Args> struct caller<void, type_list<>, Args...> {
404 static constexpr bool is_callable = false;
405 };
406
407 template<class List, class...Args>
408 struct caller<
409 std::enable_if_t< is_callable_v<Caller, type_list_member<0, List>, Args...>>,
410 List,
411 Args...
412 >
413 {
414 static constexpr bool is_callable = true;
415 using type = type_list_member<0, List>;
416 };
417
418 using types_list = flatten_t<T...>;
419
420public:
421 template<class...Args>
422 static constexpr bool is_matched_v =
423 caller<void, types_list, Args...>::is_callable;
424
425 template<class...Args>
426 static constexpr bool is_matched(Args&&...) {
427 return is_matched_v<Args...>;
428 }
429
430 template<class...Args>
431 using matched_type = typename caller<void, types_list, Args...>::type;
432
433 template<class...Args>
434 static constexpr decltype(auto) call(Args&&...args) {
435 static_assert(
436 is_matched_v<Args...>,
437 "None of the types is callable with these argument types."
438 );
439 return Caller::template caller<matched_type<Args...>, void, Args...>
440 ::call(std::forward<Args>(args)...);
441 }
442
443 template<class...Args>
444 constexpr decltype(auto) operator()(Args&&...args) const {
445 return call(std::forward<Args>(args)...);
446 }
447
448 template<class F>
449 static constexpr
450 fallback_caller<chain_caller, std::remove_reference_t<F>>
451 fallback(F&& functor) {
452 return std::forward<F>(functor);
453 }
454
455 template<class...Args>
456 static matched_type<Args...> declval_matched(Args&&...) noexcept;
457};
458
459
460} }
461
462
464
465
466
467
506#define UGMISC_NAMED_MEMBER_STATIC_METHOD_CALL(TEMPLATENAME, NAME) \
507 UGMISC__DECL_MEMBER_CALLER_TYPE(TEMPLATENAME, NAME); \
508 template<class...T> class TEMPLATENAME \
509 : public ::ugmisc::member_::chain_caller< \
510 UGMISC__MEMBER_CALLER_TYPE_NAME(TEMPLATENAME), \
511 T... \
512 > \
513 { \
514 static constexpr const char *template_name = #TEMPLATENAME; \
515 static constexpr const char *function_name = #NAME; \
516 }
517
518
526#define UGMISC_MEMBER_STATIC_METHOD_CALL(NAME) \
527 UGMISC_NAMED_MEMBER_STATIC_METHOD_CALL(member_call_##NAME, NAME)
Definition member.hpp:67
static constexpr decltype(auto) call(U &&...args)
static constexpr auto fallback(F &&functor)
??? matched_type
Definition member.hpp:129
static matched_type< U... > declval_matched(U &&...) noexcept
static constexpr bool is_matched(U &&...)
static constexpr bool is_matched_v
Definition member.hpp:136
Lists of types which may be used in some of the ugmisc templates where a single type would usually be...