ugmisc 0.2-76
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
141
142#include "ugmisc/typelist.hpp"
143#include <utility>
144
145
146
147
148#ifdef UGMISC_DOCS
149#error
150#endif
151
152
153
154
165#define UGMISC_DECL_MEMBER_ACCESS(TNAME, NAME) \
166class TNAME { \
167 struct ugmisc_priv { \
168 /* Static method call support. */ \
169 \
170 template<class T, class, class...A> \
171 struct static_caller { \
172 static constexpr bool is_callable = false; \
173 }; \
174 \
175 template<class T, class...A> \
176 struct static_caller<T, std::void_t<decltype(T::NAME(std::declval<A>()...))>, A...> { \
177 static constexpr bool is_callable = true; \
178 \
179 static constexpr decltype(auto) call(A...args) { \
180 return T::NAME(std::forward<A>(args)...); \
181 } \
182 }; \
183 \
184 /* Non static method call support. */ \
185 \
186 template<class T, class, class...A> \
187 struct caller { \
188 static constexpr bool is_callable = false; \
189 }; \
190 \
191 template<class T, class...A> \
192 struct caller<T, std::void_t<decltype(std::declval<T>().NAME(std::declval<A>()...))>, A...> { \
193 static constexpr bool is_callable = true; \
194 \
195 static constexpr decltype(auto) call(T& obj, A...args) { \
196 return std::forward<T>(obj).NAME(std::forward<A>(args)...); \
197 } \
198 }; \
199 \
200 /* Static data reference support. */ \
201 \
202 template<class T, class=void> \
203 struct static_member { \
204 static constexpr bool has_member = false; \
205 }; \
206 \
207 template<class T> \
208 struct static_member<T, std::void_t<decltype(T::NAME)>> { \
209 static constexpr bool has_member = true; \
210 \
211 static constexpr auto& get() { \
212 return T::NAME; \
213 } \
214 }; \
215 \
216 /* Non static data reference support. */ \
217 \
218 template<class T, class=void> \
219 struct member { \
220 static constexpr bool has_member = false; \
221 }; \
222 \
223 template<class T> \
224 struct member<T, std::void_t<decltype(std::declval<T>().NAME)>> { \
225 static constexpr bool has_member = true; \
226 \
227 static constexpr auto& get(T& obj) { \
228 return obj.NAME; \
229 } \
230 \
231 using member_type = decltype(std::declval<std::remove_reference_t<T>>().NAME); \
232 }; \
233 /* Type support. */ \
234 \
235 template< class T, class=void > struct GetType { \
236 static constexpr bool has_member_type = false; \
237 using safe_type = void; \
238 }; \
239 \
240 template< class T > struct GetType< T, std::void_t< typename T::NAME > > { \
241 static constexpr bool has_member_type = true; \
242 using safe_type = typename T::NAME; \
243 using type = typename T::NAME; \
244 }; \
245 \
246 }; \
247public: \
248 struct ugmisc { \
249 /* Static method call. */ \
250 template<class T, class...A> static constexpr bool is_static_callable = \
251 ugmisc_priv::static_caller<T, void, A...>::is_callable; \
252 \
253 template<class T, class...A> \
254 static constexpr auto static_call(A&&...args) \
255 -> decltype( \
256 ugmisc_priv::static_caller<T, void, A...>::call( \
257 std::forward<A>(args)... \
258 )) \
259 { \
260 return ugmisc_priv::static_caller<T, void, A...>::call( \
261 std::forward<A>(args)... \
262 ); \
263 } \
264 \
265 /* Non static method call. */ \
266 template<class T, class...A> static constexpr bool is_callable = \
267 ugmisc_priv::caller<T, void, A...>::is_callable; \
268 \
269 template<class T, class...A> \
270 static constexpr auto call(T& obj, A&&...args) \
271 -> decltype( \
272 ugmisc_priv::caller<T, void, A...>::call( \
273 obj, \
274 std::forward<A>(args)... \
275 )) \
276 { \
277 return ugmisc_priv::caller<T, void, A...>::call( \
278 obj, \
279 std::forward<A>(args)... \
280 ); \
281 } \
282 \
283 /* Static member reference. */ \
284 template< class T > \
285 static constexpr bool has_static_member \
286 = ugmisc_priv::static_member<T>::has_member; \
287 template< class T> \
288 static constexpr auto& static_get() { \
289 return ugmisc_priv::static_member<T>::get(); \
290 } \
291 \
292 /* Non static member reference. */ \
293 template< class T > \
294 static constexpr bool has_member \
295 = ugmisc_priv::member<T>::has_member; \
296 template< class T > \
297 using member_type = typename ugmisc_priv::member<T>::member_type; \
298 template< class T> \
299 static constexpr auto& get(T&& obj) { \
300 return ugmisc_priv::member<T>::get(obj); \
301 } \
302 \
303 /* Type. */ \
304 \
305 template< class T > using type = typename ugmisc_priv::GetType<T>::type; \
306 template< class T > using safe_type = \
307 typename ugmisc_priv::GetType<T>::safe_type; \
308 template< class T > static constexpr bool has_member_type = \
309 ugmisc_priv::GetType<T>::has_member_type; \
310 }; \
311}
312
313
314
315
320#define UGMISC_DECL_STATIC_MEMBER_CALLER(TNAME, NAME) \
321 UGMISC_DECL_MEMBER_ACCESS(TNAME, NAME)
322
323
324
325
330#define UGMISC_DECL_MEMBER_TYPE_ALIAS(TNAME, NAME) \
331 UGMISC_DECL_MEMBER_ACCESS(TNAME, NAME)
332
333
334
335
340#define UGMISC_DECL_STATIC_MEMBER_ACCESSOR(TNAME, NAME) \
341 UGMISC_DECL_MEMBER_ACCESS(TNAME, NAME)
342
343
344
345
346namespace ugmisc {
347
348
349
350
354template<class T>
356 using type = T;
357};
358
359
360
361
363namespace member_ {
364
365
366
367
368template<class T>
369struct get_is_default_type : public std::false_type {};
370
371template<class T>
372struct get_is_default_type< default_type<T> > : public std::true_type {};
373
374template<class T>
375struct get_is_not_default_type {
376 using type = bool;
377 static constexpr bool value = !get_is_default_type<T>::value;
378};
379
380template<class T> static inline bool is_default_type =
381 get_is_default_type<T>::value;
382
383
384
385
400template<class StaticCaller, class Functor>
401class fallback_caller {
402 Functor m_functor;
403
404 /*
405 * The use of Dummy* for the first override and Dummy for the second, makes
406 * the first more specific.
407 */
408 template<class Dummy, class...T>
409 constexpr auto forward(Dummy*, T&&...args) const
410 -> decltype(m_functor(std::forward<T>(args)...))
411 {
412 return m_functor(std::forward<T>(args)...);
413 }
414
415 template<class Dummy, class...T>
416 constexpr decltype(auto) forward(Dummy, T&&...args) const {
417 return m_functor();
418 }
419
420
421public:
422 constexpr fallback_caller(const Functor& f) : m_functor(f) {}
423 constexpr fallback_caller(Functor&& f) : m_functor(std::move(f)) {}
424
425 fallback_caller(fallback_caller&&) = default;
426 fallback_caller(const fallback_caller&) = delete;
427
428 template<class...T>
429 constexpr decltype(auto) call(T&&...args) const {
430 if constexpr ( StaticCaller::template is_matched_v<T...> ) {
431 return StaticCaller::call(std::forward<T>(args)...);
432 } else {
433 auto dummy = (int*)nullptr;
434 return forward(dummy, std::forward<T>(args)...);
435 }
436 }
437
438 template<class...T>
439 constexpr decltype(auto) operator()(T&&...args) const {
440 return call(std::forward<T>(args)...);
441 }
442};
443
444
445
446
447
448} /* member_ (::ugmisc::member_) */
449
450
452
453} /* ::ugmisc */
454
455
456
457
462#define UGMISC_NAMED_MEMBER_TYPE_TEST(TEMPLATENAME, ALIASNAME, HASMEMBERNAME, NAME) \
463 UGMISC__DECL_MEMBER_TYPEDEF_TYPE(TEMPLATENAME, NAME); \
464 \
465 template<class T, class D = void> struct TEMPLATENAME : \
466 public ::ugmisc::member_type_access<UGMISC__MEMBER_TYPEDEF_TYPE_NAME(TEMPLATENAME), T, ::ugmisc::default_type<D>> \
467 { \
468 }; \
469 \
470 template<class T, class D = void> using ALIASNAME = \
471 typename TEMPLATENAME<T, D>::type; \
472 template<class...T> static constexpr bool HASMEMBERNAME = \
473 TEMPLATENAME<::ugmisc::type_list<T...>>::has_member
474
475
476
481#define UGMISC_MEMBER_TYPE_TEST(NAME) \
482 UGMISC_NAMED_MEMBER_TYPE_TEST(member_type_test_##NAME, member_type_##NAME, has_member_type_##NAME, NAME)
483
484
485
487
488#define UGMISC__MEMBER_CALLER_TYPE_NAME(TNAME) _ugmisc_caller_##TNAME
489
493#define UGMISC__DECL_MEMBER_CALLER_TYPE(TNAME, NAME) \
494UGMISC_DECL_STATIC_MEMBER_CALLER(UGMISC__MEMBER_CALLER_TYPE_NAME(TNAME), NAME)
495
497#define UGMISC__MEMBER_TYPEDEF_TYPE_NAME(TNAME) _ugmisc_typedef_##TNAME
498
502#define UGMISC__DECL_MEMBER_TYPEDEF_TYPE(TNAME, NAME) \
503UGMISC_DECL_MEMBER_TYPE_ALIAS(UGMISC__MEMBER_TYPEDEF_TYPE_NAME(TNAME), NAME)
504
505
506
507
508namespace ugmisc {
509namespace member_ {
510
511
512template<class Access, class T, class...A>
513inline constexpr bool is_static_callable_v =
514 Access::ugmisc::template is_static_callable<T, A...>;
515
516
517template<class Access, class T, class...A>
518constexpr bool is_static_callable(A&&...) {
519 return is_static_callable_v<Access, T, A...>;
520}
521
522
523} /* member_ (::ugmisc::member_) */
525
526
527
592template<class Access, class...T>
594private:
595 template<class V, class List, class...Args>
596 struct caller
597 : public caller<V, type_list_remove_prefix<1, List>, Args...> {
598 };
599
600 template<class...Args> struct caller<void, type_list<>, Args...> {
601 static constexpr bool is_callable = false;
602 using safe_type = void;
603 };
604
605 template<class List, class...Args>
606 struct caller<
607 std::enable_if_t< member_::is_static_callable_v<Access, type_list_member<0, List>, Args...>>,
608 List,
609 Args...
610 >
611 {
612 static constexpr bool is_callable = true;
613 using type = type_list_member<0, List>;
614 using safe_type = void;
615 };
616
617 using types_list = flatten_t<T...>;
618
619public:
625 template<class...Args>
626 static constexpr bool is_matched_v =
627 caller<void, types_list, Args...>::is_callable;
628
632 template<class...Args>
633 static constexpr bool is_matched(Args&&...) {
634 return is_matched_v<Args...>;
635 }
636
641 template<class...Args>
642 using matched_type = typename caller<void, types_list, Args...>::type;
643
650 template<class...Args>
652 typename caller<void, types_list, Args...>::safe_type;
653
663 template<class...Args>
664 static constexpr decltype(auto) call(Args&&...args) {
665 using type = matched_type<Args...>;
666 static_assert(
667 is_matched_v<Args...>,
668 "None of the types is callable with these argument types."
669 );
670 return Access::ugmisc::template static_call<type>(std::forward<Args>(args)...);
671 }
672
678 template<class...Args>
679 constexpr decltype(auto) operator()(Args&&...args) const {
680 return call(std::forward<Args>(args)...);
681 }
682
688 template<class F>
689 static constexpr
690 member_::fallback_caller<static_member_caller, std::remove_reference_t<F>>
691 fallback(F&& functor) {
692 return std::forward<F>(functor);
693 }
694
699 template<class...Args>
700 static matched_type<Args...> declval_matched(Args&&...) noexcept;
701
706 template<class...Args>
707 static matched_type<Args...> declval_matched() noexcept;
708
714 template<class...Args>
715 static safe_matched_type<Args...> safe_declval_matched(Args&&...) noexcept;
716
720 template<class...Args>
721 static safe_matched_type<Args...> safe_declval_matched() noexcept;
722};
723
724
725
726
761template<class Access>
763private:
764 /*
765 * A wrapped objects instance contains references to objects.
766 * It only exists briefly. It is instantiated explicitly, because we want
767 * to know which objects were originally lvalues (those will be passed as
768 * reference types).
769 * However we always store references to the objects.
770 */
771 template<class...T>
772 struct wrapped_objects_base {
773 protected:
774 static_assert(
775 sizeof...(T) == 0,
776 "A specialisation should have been used instead of this template."
777 );
778
779 template<class...A> static constexpr bool is_matched_v = false;
780 template<class...A> static constexpr bool is_matched(A&&...) {
781 return false;
782 }
783
784 wrapped_objects_base() = default;
785 wrapped_objects_base(const wrapped_objects_base&) = default;
786
787 template<class...A>
788 constexpr void call(A&&...) const {
789 static_assert(false, "There are no more objects to call.");
790 }
791
792 static constexpr bool safe_refs = true;
793
794 template<class...A>
795 static constexpr bool matched_here = false;
796 };
797
798 template<class T1, class...T>
799 struct wrapped_objects_base<T1, T...> : public wrapped_objects_base<T...>
800 {
801 private:
802 T1& obj_ref;
803
804 protected:
805 static constexpr bool safe_refs =
806 std::is_lvalue_reference_v<T1> &&
807 wrapped_objects_base<T...>::safe_refs;
808 ;
809
810 template<class...A>
811 static constexpr bool matched_here =
812 Access::ugmisc::template is_callable<T1, A...>;
813
814 template<class...A>
815 constexpr decltype(auto) call(A&&...args) const {
816 if constexpr ( matched_here<A...> ) {
817 return Access::ugmisc::template call(
818 obj_ref,
819 std::forward<A>(args)...
820 );
821 } else {
822 return this->wrapped_objects_base<T...>::call(std::forward<A>(args)...);
823 }
824 }
825
826 public:
827 constexpr wrapped_objects_base(T1& obj, T&...t)
828 : wrapped_objects_base<T...>(t...), obj_ref(obj)
829 {}
830
831 wrapped_objects_base(wrapped_objects_base&&) = default;
832
833 constexpr wrapped_objects_base(const wrapped_objects_base& other)
834 : wrapped_objects_base<T...>((wrapped_objects_base<T...>)other),
835 obj_ref(other.obj_ref)
836 {
837 static_assert(
838 safe_refs,
839 "Can't copy a member_caller::wrapped_objects if the "
840 "referenced objects aren't all lvalues."
841 );
842 }
843
844 template<class...A>
845 static constexpr bool is_matched_v =
846 matched_here<A...> ||
847 wrapped_objects_base<T...>::template matched_here<A...>;
848
849 template<class...A>
850 static constexpr bool is_matched(A&&...) {
851 return is_matched_v<A...>;
852 }
853 };
854
855 /*
856 * wrapped_objects with a functor is like wrapped_objects without one, but
857 * it will default to calling the functor.
858 */
859 template<class F, class...T>
860 class wrapped_objects : public wrapped_objects<void, T...> {
861 F functor;
862 using wrapped_objects<void, T...>::wrapped_objects;
863
864 template<class, class...A> struct forwarder {
865 static constexpr decltype(auto) call(F& f, A&...args) {
866 return f();
867 }
868 };
869
870 template<class...A>
871 struct forwarder<
872 std::void_t< decltype(std::declval<F>()(std::declval<A>()...)) >,
873 A...
874 >
875 {
876 static constexpr decltype(auto) call(F& f, A&...args) {
877 return f(std::forward<A>(args)...);
878 }
879 };
880
881 template<class...A>
882 constexpr decltype(auto) call_default(A&&...args) const {
883 return forwarder<void, A...>::call(functor, args...);
884 }
885
886 public:
887 constexpr wrapped_objects(F& f, T...t)
888 : wrapped_objects<void, T...>(t...), functor(f)
889 {}
890
891 template<class...A>
892 constexpr decltype(auto) operator()(A&&...args) const {
893 if constexpr ( wrapped_objects::template is_matched_v<A...> ) {
894 return this->call( std::forward<A>(args)... );
895 } else {
896 return call_default(std::forward<A>(args)...);
897 }
898 }
899 };
900
901 template<class...T>
902 class wrapped_objects<void, T...> : public wrapped_objects_base<T...> {
903 public:
904 using wrapped_objects_base<T...>::wrapped_objects_base;
905
906 template<class...A>
907 constexpr decltype(auto) operator() (A&&...args) const {
908 return
909 this->call(std::forward<A>(args)...);
910 }
911 };
912
913 /*
914 * This only has the job of creating a wrapped_objects.
915 * It is intended to be a short lived object.
916 */
917 template<class F>
918 class default_function {
919 F& functor_ref;
920 public:
921 constexpr default_function(F& f) : functor_ref(f) {}
922 default_function(default_function&&) = default;
923 default_function(const default_function&) = delete;
924
925 template<class...T>
926 constexpr wrapped_objects<F, T...> operator() (T&&...objs) const {
927 return {functor_ref, objs...};
928 }
929 };
930
931public:
932 /*
933 * The public methods are static because member_caller itself holds all its
934 * defining characteristics in its type.
935 */
936
941 template<class F>
942 static constexpr default_function<F> fallback(F&& f) { return f; }
943
947 template<class...T>
948 static constexpr wrapped_objects<void, T...> with(T&&...objs) {
949 return {objs...};
950 }
951
952 template<class...T>
953 constexpr auto operator() (T&&...objs) const { return with<T...>(objs...); }
954};
955
956
957
958
967
968
969
970
1053template<class Access, member_value_copy CopyValue = MEMBER_COPY_AUTO>
1055 static_assert(
1056 (CopyValue == MEMBER_COPY_AUTO) ||
1057 (CopyValue == MEMBER_COPY_ALWAYS) ||
1058 (CopyValue == MEMBER_COPY_NEVER)
1059 );
1060private:
1061 struct empty {
1062 template<class F, class...A>
1063 constexpr decltype(auto) get(F&& func, A&&...args) const {
1064 return std::forward<F>(func)(std::forward<A>(args)...);
1065 }
1066
1067 static constexpr bool has_member = false;
1068
1069 constexpr void get() const {
1070 static_assert(
1071 false,
1072 "Can't get member that was not found in any object."
1073 );
1074 }
1075 };
1076
1077 template<class T>
1078 class wrapped_object_member {
1079 using object_type = T;
1080
1081 // The actual type of the member, as declared in T's definition.
1082 using member_type = typename Access::ugmisc::template member_type<T>;
1083
1084 using effective_member_type =
1085 decltype(Access::ugmisc::get(std::declval<T&>()));
1086
1087 using deref_effective_member_type =
1088 std::remove_reference_t<effective_member_type>;
1089
1090 static constexpr bool rvalue_object =
1091 !std::is_lvalue_reference_v<object_type>;
1092
1093 static constexpr bool const_object =
1094 std::is_const_v<object_type>;
1095
1096 static constexpr bool volatile_object =
1097 std::is_volatile_v<object_type>;
1098
1099 static constexpr bool member_is_reference =
1100 std::is_lvalue_reference_v<member_type>;
1101
1102 static constexpr bool volatile_member =
1103 std::is_volatile_v<deref_effective_member_type>;
1104
1105 static constexpr bool const_member =
1106 std::is_const_v<deref_effective_member_type>;
1107
1108 static constexpr bool rvalue_member =
1109 (! member_is_reference) && rvalue_object;
1110
1111 /*
1112 * copy_member == true: the member value is copied into the wrapper,
1113 * and returned by copy from get().
1114 */
1115 static constexpr bool copy_member =
1116 (CopyValue == MEMBER_COPY_ALWAYS)
1117 || (
1118 (CopyValue != MEMBER_COPY_NEVER)
1119 && (!volatile_member)
1120 && (const_member || rvalue_member)
1121 && std::is_trivially_copyable_v< member_type >
1122 );
1123
1124 /*
1125 * return rvalue_member == true: a reference to the member is stored,
1126 * and an rvalue reference is returned from get().
1127 */
1128 static constexpr bool return_rvalue_member =
1129 (!copy_member) && rvalue_member;
1130
1131 static constexpr bool return_lvalue_member =
1132 (!return_rvalue_member || copy_member);
1133
1134 using member_store_type = std::conditional_t<
1135 copy_member,
1136 const std::remove_volatile_t<deref_effective_member_type>,
1137 effective_member_type
1138 >;
1139
1140 using member_return_type = std::conditional_t<
1141 copy_member,
1142 std::remove_const_t<member_store_type>,
1143 std::conditional_t<
1144 return_rvalue_member,
1145 deref_effective_member_type&&,
1146 deref_effective_member_type&
1147 >
1148 >;
1149
1150 // This may be a copy of the member's value where that is safe to do.
1151 // Otherwise it is a reference to the member.
1152 member_store_type member;
1153 public:
1154 static constexpr bool has_member = true;
1155
1156 constexpr wrapped_object_member( object_type& obj )
1157 : member( Access::ugmisc::get(obj) )
1158 {}
1159
1160 wrapped_object_member(const wrapped_object_member&) = default;
1161 wrapped_object_member(wrapped_object_member&&) = default;
1162
1163 template<class...A>
1164 constexpr member_return_type get(A&&...args) const { return member; }
1165 };
1166
1167 static constexpr empty find_ref() { return {}; }
1168
1169 template<class T1, class...T>
1170 static constexpr auto find_ref(T1&& obj, T&&...objs) {
1171 if constexpr ( Access::ugmisc::template has_member<T1> ) {
1172 return wrapped_object_member<T1>{ obj };
1173 } else {
1174 return find_ref(std::forward<T>(objs)...);
1175 }
1176 }
1177
1178public:
1179 /*
1180 * The public methods are static because member_value itself holds all its
1181 * defining characteristics in its type.
1182 */
1183
1187 template<class...T>
1188 static constexpr auto with(T&&...objs) {
1189 return find_ref(std::forward<T>(objs)...);
1190 }
1191
1192 template<class...T>
1193 constexpr auto operator() (T&&...objs) const { return with<T...>(objs...); }
1194
1208
1218
1228};
1229
1230
1231
1232
1234namespace member_ {
1239template< class Access, class TypeList > class member_type_access_traits {
1240 using all_types = TypeList;
1241 using normal_types =
1242 filter_type_list<member_::get_is_default_type, all_types, invert_test>;
1243 using default_types =
1244 filter_type_list<member_::get_is_default_type, all_types>;
1245
1246 static_assert( default_types::size <= 1 );
1247 static_assert( default_types::size + normal_types::size == all_types::size );
1248
1249 using access = Access;
1250
1251 template<bool Found, class U> struct result {
1252 static constexpr bool found = Found;
1253 using type = U;
1254 };
1255
1256 /*
1257 * This allows us to avoid instantiating type_list_member<0, seq> where seq
1258 * is empty.
1259 */
1260 template< class seq = normal_types >
1261 static constexpr auto find_type_pair() {
1262
1263 if constexpr ( seq::size == 0 ) {
1264 return result<false, void>{};
1265 } else {
1266 using first_type = type_list_member<0, seq>;
1267 if constexpr ( access::ugmisc::template has_member_type<first_type> ) {
1268 return result<
1269 true,
1270 typename access::ugmisc::template type<first_type>
1271 >{};
1272 } else {
1273 return find_type_pair< type_list_remove_prefix<1, seq> >();
1274 }
1275 }
1276 }
1277
1278 using result_t = decltype(find_type_pair());
1279
1280 /*
1281 * This allows us to avoid instantiating type_list_member<default_types>
1282 * when default_types is empty.
1283 */
1284 static constexpr auto find_default_type_pair() {
1285 if constexpr ( default_types::size ) {
1286 return result<true, type_list_member<0, default_types>>{};
1287 } else {
1288 return result<false, void>{};
1289 }
1290 }
1291
1292 using default_t = decltype(find_default_type_pair());
1293
1294
1295public:
1296 static constexpr bool has_member = result_t::found;
1297 static constexpr bool has_default = default_t::found;
1298 static constexpr bool has_type = has_member || has_default;
1299 using type = std::conditional_t<
1300 has_member,
1301 typename result_t::type,
1302 typename default_t::type
1303 >;
1304};
1305
1306
1307
1308
1313template<
1314 class Access,
1315 class TypeList,
1316 bool HasType = member_type_access_traits<Access, TypeList>::has_type
1317 >
1318struct member_type_access {
1319 static_assert( ! HasType, "There is a missing specialisation." );
1320 static constexpr bool has_member = false;
1321 static constexpr bool has_default = false;
1322 static constexpr bool has_type = false;
1323 // Don't declare type!
1324 using safe_type = void;
1325};
1326
1327
1328template<class Access, class TypeList>
1329struct member_type_access<Access, TypeList, true> {
1330 static constexpr bool has_member
1331 = member_type_access_traits<Access, TypeList>::has_member;
1332
1333 static constexpr bool has_default
1334 = member_type_access_traits<Access, TypeList>::has_default;
1335
1336 static constexpr bool has_type = true;
1337
1338 using type
1339 = typename member_type_access_traits<Access, TypeList>::type;
1340
1341 using safe_type = type;
1342};
1343
1344
1345
1346
1347template<class Access, class...T>
1348class static_member_value_base {
1349 template<class U> struct access {
1350 using type = U;
1351 static constexpr bool has_member = Access::ugmisc::template has_static_member<U>;
1352 static constexpr auto& get() { return Access::ugmisc::template static_get<U>(); }
1353 };
1354
1355 struct void_wrapper {
1356 using type = void;
1357 };
1358
1359 template<bool Found, class Type=void_wrapper>
1360 struct result {
1361 using type = Type;
1362 static constexpr bool found = Found;
1363 };
1364
1365 using accessor_types = flatten_apply_each_class<access, T...>;
1366
1367 template<class accessors = accessor_types>
1368 static constexpr auto find_matching_type() {
1369 if constexpr ( accessors::size == 0 ) {
1370 return result<false>{};
1371 } else {
1372 using first_type = type_list_member<0, accessors>;
1373 if constexpr ( first_type::has_member ) {
1374 return result<true, first_type>{};
1375 } else {
1376 return find_matching_type<type_list_remove_prefix<1, accessors>>();
1377 }
1378 }
1379 }
1380
1381 using result_type = decltype(find_matching_type());
1382 using getter_type = typename result_type::type;
1383
1384public:
1385 static constexpr bool has_member = result_type::found;
1386
1387 template<class F, class...A>
1388 static constexpr decltype(auto) get(F&& default_get, A&&...args) {
1389 if constexpr ( has_member ) {
1390 return getter_type::get();
1391 } else {
1392 return default_get(std::forward<A>(args)...);
1393 }
1394 }
1395
1396 static constexpr auto& get() { return getter_type::get(); }
1397
1398 using safe_matched_type = typename getter_type::type;
1399};
1400
1401
1402template<bool WithType, class Access, class...T>
1403struct static_member_value;
1404
1405template<class Access, class...T>
1406struct static_member_value<true, Access, T...>
1407: public static_member_value_base<Access, T...>
1408{
1409 using matched_type =
1410 typename static_member_value_base<Access, T...>::safe_matched_type;
1411};
1412
1413template<class Access, class...T>
1414struct static_member_value<false, Access, T...>
1415: public static_member_value_base<Access, T...>
1416{ };
1417
1418
1419template<class Access, class...T>
1420using static_member_value_t =
1421 static_member_value<
1422 static_member_value_base<Access, T...>::has_member,
1423 Access, T...
1424 >;
1425
1426
1427} /* member_ (::ugmisc::member_) */
1429
1430
1431
1432#ifndef UGMISC_DOCS
1433template< class Access, class...T > class member_type_access
1434: public member_::member_type_access<Access, flatten_t<T...>>
1435{
1436};
1437#else
1438
1474template< class Access, class...T > struct member_type_access {
1479 static constexpr bool has_member = ???;
1480
1486 static constexpr bool has_default = ???;
1487
1492 static constexpr bool has_type = has_member || has_default;
1493
1505 using type = ???;
1506
1511 using safe_type = ???;
1512};
1513#endif
1514
1515
1516
1517
1555template<class Access, class...T>
1556struct static_member_value : public member_::static_member_value_t<Access, T...>
1557{
1558#ifdef UGMISC_DOCS
1563 static constexpr bool has_member = ???;
1564
1575 template<class F, class...A>
1576 static constexpr decltype(auto) get(F&& default_get, A&&...args);
1577
1583 static constexpr auto& get() { return getter_type::get(); }
1584
1592
1598 using matched_type = ???;
1599#endif
1600};
1601
1602
1603
1604
1608
1609
1610
1611
1612}
1613
1614
1615
1616
1622#define UGMISC_NAMED_MEMBER_STATIC_METHOD_CALL(TEMPLATENAME, NAME) \
1623 UGMISC__DECL_MEMBER_CALLER_TYPE(TEMPLATENAME, NAME); \
1624 template<class...T> class TEMPLATENAME \
1625 : public ::ugmisc::static_member_caller< \
1626 UGMISC__MEMBER_CALLER_TYPE_NAME(TEMPLATENAME), \
1627 T... \
1628 > \
1629 { \
1630 static constexpr const char *template_name = #TEMPLATENAME; \
1631 static constexpr const char *function_name = #NAME; \
1632 }
1633
1634
1640#define UGMISC_MEMBER_STATIC_METHOD_CALL(NAME) \
1641 UGMISC_NAMED_MEMBER_STATIC_METHOD_CALL(member_call_##NAME, NAME)
member_value_copy
Definition member.hpp:962
@ MEMBER_COPY_AUTO
Default. Copy value if safe and trivial to do so.
Definition member.hpp:963
@ MEMBER_COPY_ALWAYS
Always copy the value.
Definition member.hpp:965
@ MEMBER_COPY_NEVER
Always take a reference to the original object.
Definition member.hpp:964
Definition member.hpp:762
static constexpr wrapped_objects< void, T... > with(T &&...objs)
Definition member.hpp:948
static constexpr default_function< F > fallback(F &&f)
Definition member.hpp:942
Definition member.hpp:1474
static constexpr bool has_type
Definition member.hpp:1492
??? type
Definition member.hpp:1505
static constexpr bool has_default
Definition member.hpp:1486
static constexpr bool has_member
Definition member.hpp:1479
??? safe_type
Definition member.hpp:1511
Definition member.hpp:1054
static constexpr member_value< Access, MEMBER_COPY_ALWAYS > copy_always
Definition member.hpp:1217
static constexpr auto with(T &&...objs)
Definition member.hpp:1188
static constexpr member_value< Access, MEMBER_COPY_NEVER > copy_never
Definition member.hpp:1227
static constexpr member_value< Access, MEMBER_COPY_AUTO > copy_auto
Definition member.hpp:1207
Definition member.hpp:593
static constexpr bool is_matched(Args &&...)
Definition member.hpp:633
static constexpr member_::fallback_caller< static_member_caller, std::remove_reference_t< F > > fallback(F &&functor)
Definition member.hpp:691
typename caller< void, types_list, Args... >::safe_type safe_matched_type
Definition member.hpp:651
typename caller< void, types_list, Args... >::type matched_type
Definition member.hpp:642
static constexpr decltype(auto) call(Args &&...args)
Definition member.hpp:664
static safe_matched_type< Args... > safe_declval_matched(Args &&...) noexcept
static matched_type< Args... > declval_matched(Args &&...) noexcept
static constexpr bool is_matched_v
Definition member.hpp:626
Definition member.hpp:1557
static constexpr auto & get()
Definition member.hpp:1583
static constexpr bool has_member
Definition member.hpp:1563
static constexpr decltype(auto) get(F &&default_get, A &&...args)
??? matched_type
Definition member.hpp:1598
??? safe_matched_type
Definition member.hpp:1591
Definition member.hpp:355
Lists of types which may be used in some of the ugmisc templates where a single type would usually be...
type_list_apply_each_class< F, flatten_t< T... > > flatten_apply_each_class
Definition typelist.hpp:371