UgMisc 0.2-110
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#ifndef UGMISC_MEMBER_HPP
25#define UGMISC_MEMBER_HPP
26
142
143#include "ugmisc/typelist.hpp"
144#include <utility>
145
146
147
148
149#ifdef UGMISC_DOCS
150#error
151#endif
152
153
154
155
166#define UGMISC_DECL_MEMBER_ACCESS(TNAME, NAME) \
167class TNAME { \
168 struct ugmisc_priv { \
169 /* Static method call support. */ \
170 \
171 template<class T, class, class...A> \
172 struct static_caller { \
173 static constexpr bool is_callable = false; \
174 }; \
175 \
176 template<class T, class...A> \
177 struct static_caller<T, std::void_t<decltype(T::NAME(std::declval<A>()...))>, A...> { \
178 static constexpr bool is_callable = true; \
179 \
180 static constexpr decltype(auto) call(A...args) { \
181 return T::NAME(std::forward<A>(args)...); \
182 } \
183 }; \
184 \
185 /* Non static method call support. */ \
186 \
187 template<class T, class, class...A> \
188 struct caller { \
189 static constexpr bool is_callable = false; \
190 }; \
191 \
192 template<class T, class...A> \
193 struct caller<T, std::void_t<decltype(std::declval<T>().NAME(std::declval<A>()...))>, A...> { \
194 static constexpr bool is_callable = true; \
195 \
196 static constexpr decltype(auto) call(T& obj, A...args) { \
197 return std::forward<T>(obj).NAME(std::forward<A>(args)...); \
198 } \
199 }; \
200 \
201 /* Static data reference support. */ \
202 \
203 template<class T, class=void> \
204 struct static_member { \
205 static constexpr bool has_member = false; \
206 }; \
207 \
208 template<class T> \
209 struct static_member<T, std::void_t<decltype(T::NAME)>> { \
210 static constexpr bool has_member = true; \
211 \
212 static constexpr auto& get() { \
213 return T::NAME; \
214 } \
215 }; \
216 \
217 /* Non static data reference support. */ \
218 \
219 template<class T, class=void> \
220 struct member { \
221 static constexpr bool has_member = false; \
222 }; \
223 \
224 template<class T> \
225 struct member<T, std::void_t<decltype(std::declval<T>().NAME)>> { \
226 static constexpr bool has_member = true; \
227 \
228 static constexpr auto& get(T& obj) { \
229 return obj.NAME; \
230 } \
231 \
232 using member_type = decltype(std::declval<std::remove_reference_t<T>>().NAME); \
233 }; \
234 /* Type support. */ \
235 \
236 template< class T, class=void > struct GetType { \
237 static constexpr bool has_member_type = false; \
238 using safe_type = void; \
239 }; \
240 \
241 template< class T > struct GetType< T, std::void_t< typename T::NAME > > { \
242 static constexpr bool has_member_type = true; \
243 using safe_type = typename T::NAME; \
244 using type = typename T::NAME; \
245 }; \
246 \
247 }; \
248public: \
249 struct ugmisc { \
250 /* Static method call. */ \
251 template<class T, class...A> static constexpr bool is_static_callable = \
252 ugmisc_priv::static_caller<T, void, A...>::is_callable; \
253 \
254 template<class T, class...A> \
255 static constexpr auto static_call(A&&...args) \
256 -> decltype( \
257 ugmisc_priv::static_caller<T, void, A...>::call( \
258 std::forward<A>(args)... \
259 )) \
260 { \
261 return ugmisc_priv::static_caller<T, void, A...>::call( \
262 std::forward<A>(args)... \
263 ); \
264 } \
265 \
266 /* Non static method call. */ \
267 template<class T, class...A> static constexpr bool is_callable = \
268 ugmisc_priv::caller<T, void, A...>::is_callable; \
269 \
270 template<class T, class...A> \
271 static constexpr auto call(T& obj, A&&...args) \
272 -> decltype( \
273 ugmisc_priv::caller<T, void, A...>::call( \
274 obj, \
275 std::forward<A>(args)... \
276 )) \
277 { \
278 return ugmisc_priv::caller<T, void, A...>::call( \
279 obj, \
280 std::forward<A>(args)... \
281 ); \
282 } \
283 \
284 /* Static member reference. */ \
285 template< class T > \
286 static constexpr bool has_static_member \
287 = ugmisc_priv::static_member<T>::has_member; \
288 template< class T> \
289 static constexpr auto& static_get() { \
290 return ugmisc_priv::static_member<T>::get(); \
291 } \
292 \
293 /* Non static member reference. */ \
294 template< class T > \
295 static constexpr bool has_member \
296 = ugmisc_priv::member<T>::has_member; \
297 template< class T > \
298 using member_type = typename ugmisc_priv::member<T>::member_type; \
299 template< class T> \
300 static constexpr auto& get(T&& obj) { \
301 return ugmisc_priv::member<T>::get(obj); \
302 } \
303 \
304 /* Type. */ \
305 \
306 template< class T > using type = typename ugmisc_priv::GetType<T>::type; \
307 template< class T > using safe_type = \
308 typename ugmisc_priv::GetType<T>::safe_type; \
309 template< class T > static constexpr bool has_member_type = \
310 ugmisc_priv::GetType<T>::has_member_type; \
311 }; \
312}
313
314
315
316
317namespace ugmisc {
318
319
320
321
325template<class T>
327 using type = T;
328};
329
330
331
332
334namespace member_ {
335
336
337
338
339template<class T>
340struct get_is_default_type : public std::false_type {};
341
342template<class T>
343struct get_is_default_type< default_type<T> > : public std::true_type {};
344
345template<class T>
346struct get_is_not_default_type {
347 using type = bool;
348 static constexpr bool value = !get_is_default_type<T>::value;
349};
350
351template<class T> static inline bool is_default_type =
352 get_is_default_type<T>::value;
353
354
355
356
371template<class StaticCaller, class Functor>
372class fallback_caller {
373 Functor m_functor;
374
375 /*
376 * The use of Dummy* for the first override and Dummy for the second, makes
377 * the first more specific.
378 */
379 template<class Dummy, class...T>
380 constexpr auto forward(Dummy*, T&&...args) const
381 -> decltype(m_functor(std::forward<T>(args)...))
382 {
383 return m_functor(std::forward<T>(args)...);
384 }
385
386 template<class Dummy, class...T>
387 constexpr decltype(auto) forward(Dummy, T&&...args) const {
388 return m_functor();
389 }
390
391
392public:
393 constexpr fallback_caller(const Functor& f) : m_functor(f) {}
394 constexpr fallback_caller(Functor&& f) : m_functor(std::move(f)) {}
395
396 fallback_caller(fallback_caller&&) = default;
397 fallback_caller(const fallback_caller&) = delete;
398
399 template<class...T>
400 constexpr decltype(auto) call(T&&...args) const {
401 if constexpr ( StaticCaller::template is_matched_v<T...> ) {
402 return StaticCaller::call(std::forward<T>(args)...);
403 } else {
404 auto dummy = (int*)nullptr;
405 return forward(dummy, std::forward<T>(args)...);
406 }
407 }
408
409 template<class...T>
410 constexpr decltype(auto) operator()(T&&...args) const {
411 return call(std::forward<T>(args)...);
412 }
413};
414
415
416template<class Access, class T, class...A>
417inline constexpr bool is_static_callable_v =
418 Access::ugmisc::template is_static_callable<T, A...>;
419
420
421template<class Access, class T, class...A>
422constexpr bool is_static_callable(A&&...) {
423 return is_static_callable_v<Access, T, A...>;
424}
425
426
427} /* member_ (::ugmisc::member_) */
429
430
431
496template<class Access, class...T>
498private:
499 template<class V, class List, class...Args>
500 struct caller
501 : public caller<V, type_list_remove_prefix<1, List>, Args...> {
502 };
503
504 template<class...Args> struct caller<void, type_list<>, Args...> {
505 static constexpr bool is_callable = false;
506 using safe_type = void;
507 };
508
509 template<class List, class...Args>
510 struct caller<
511 std::enable_if_t< member_::is_static_callable_v<Access, type_list_member<0, List>, Args...>>,
512 List,
513 Args...
514 >
515 {
516 static constexpr bool is_callable = true;
517 using type = type_list_member<0, List>;
518 using safe_type = void;
519 };
520
521 using types_list = flatten_t<T...>;
522
523public:
529 template<class...Args>
530 static constexpr bool is_matched_v =
531 caller<void, types_list, Args...>::is_callable;
532
536 template<class...Args>
537 static constexpr bool is_matched(Args&&...) {
538 return is_matched_v<Args...>;
539 }
540
545 template<class...Args>
546 using matched_type = typename caller<void, types_list, Args...>::type;
547
554 template<class...Args>
555 using safe_matched_type =
556 typename caller<void, types_list, Args...>::safe_type;
557
567 template<class...Args>
568 static constexpr decltype(auto) call(Args&&...args) {
569 using type = matched_type<Args...>;
570 static_assert(
571 is_matched_v<Args...>,
572 "None of the types is callable with these argument types."
573 );
574 return Access::ugmisc::template static_call<type>(std::forward<Args>(args)...);
575 }
576
582 template<class...Args>
583 constexpr decltype(auto) operator()(Args&&...args) const {
584 return call(std::forward<Args>(args)...);
585 }
586
592 template<class F>
593 static constexpr
594 member_::fallback_caller<static_member_caller, std::remove_reference_t<F>>
595 fallback(F&& functor) {
596 return std::forward<F>(functor);
597 }
598
603 template<class...Args>
604 static matched_type<Args...> declval_matched(Args&&...) noexcept;
605
610 template<class...Args>
611 static matched_type<Args...> declval_matched() noexcept;
612
618 template<class...Args>
619 static safe_matched_type<Args...> safe_declval_matched(Args&&...) noexcept;
620
624 template<class...Args>
625 static safe_matched_type<Args...> safe_declval_matched() noexcept;
626};
627
628
629
630
665template<class Access>
667private:
668 /*
669 * A wrapped objects instance contains references to objects.
670 * It only exists briefly. It is instantiated explicitly, because we want
671 * to know which objects were originally lvalues (those will be passed as
672 * reference types).
673 * However we always store references to the objects.
674 */
675 template<class...T>
676 struct wrapped_objects_base {
677 protected:
678 static_assert(
679 sizeof...(T) == 0,
680 "A specialisation should have been used instead of this template."
681 );
682
683 template<class...A> static constexpr bool is_matched_v = false;
684 template<class...A> static constexpr bool is_matched(A&&...) {
685 return false;
686 }
687
688 wrapped_objects_base() = default;
689 wrapped_objects_base(const wrapped_objects_base&) = default;
690
691 template<class...A>
692 constexpr void call(A&&...) const {
693 static_assert(false, "There are no more objects to call.");
694 }
695
696 static constexpr bool safe_refs = true;
697
698 template<class...A>
699 static constexpr bool matched_here = false;
700 };
701
702 template<class T1, class...T>
703 struct wrapped_objects_base<T1, T...> : public wrapped_objects_base<T...>
704 {
705 private:
706 T1& obj_ref;
707
708 protected:
709 static constexpr bool safe_refs =
710 std::is_lvalue_reference_v<T1> &&
711 wrapped_objects_base<T...>::safe_refs;
712 ;
713
714 template<class...A>
715 static constexpr bool matched_here =
716 Access::ugmisc::template is_callable<T1, A...>;
717
718 template<class...A>
719 constexpr decltype(auto) call(A&&...args) const {
720 if constexpr ( matched_here<A...> ) {
721 return Access::ugmisc::template call(
722 obj_ref,
723 std::forward<A>(args)...
724 );
725 } else {
726 return this->wrapped_objects_base<T...>::call(std::forward<A>(args)...);
727 }
728 }
729
730 public:
731 constexpr wrapped_objects_base(T1& obj, T&...t)
732 : wrapped_objects_base<T...>(t...), obj_ref(obj)
733 {}
734
735 wrapped_objects_base(wrapped_objects_base&&) = default;
736
737 constexpr wrapped_objects_base(const wrapped_objects_base& other)
738 : wrapped_objects_base<T...>((wrapped_objects_base<T...>)other),
739 obj_ref(other.obj_ref)
740 {
741 static_assert(
742 safe_refs,
743 "Can't copy a member_caller::wrapped_objects if the "
744 "referenced objects aren't all lvalues."
745 );
746 }
747
748 template<class...A>
749 static constexpr bool is_matched_v =
750 matched_here<A...> ||
751 wrapped_objects_base<T...>::template matched_here<A...>;
752
753 template<class...A>
754 static constexpr bool is_matched(A&&...) {
755 return is_matched_v<A...>;
756 }
757 };
758
759 /*
760 * wrapped_objects with a functor is like wrapped_objects without one, but
761 * it will default to calling the functor.
762 */
763 template<class F, class...T>
764 class wrapped_objects : public wrapped_objects<void, T...> {
765 F functor;
766 using wrapped_objects<void, T...>::wrapped_objects;
767
768 template<class, class...A> struct forwarder {
769 static constexpr decltype(auto) call(F& f, A&...args) {
770 return f();
771 }
772 };
773
774 template<class...A>
775 struct forwarder<
776 std::void_t< decltype(std::declval<F>()(std::declval<A>()...)) >,
777 A...
778 >
779 {
780 static constexpr decltype(auto) call(F& f, A&...args) {
781 return f(std::forward<A>(args)...);
782 }
783 };
784
785 template<class...A>
786 constexpr decltype(auto) call_default(A&&...args) const {
787 return forwarder<void, A...>::call(functor, args...);
788 }
789
790 public:
791 constexpr wrapped_objects(F& f, T...t)
792 : wrapped_objects<void, T...>(t...), functor(f)
793 {}
794
795 template<class...A>
796 constexpr decltype(auto) operator()(A&&...args) const {
797 if constexpr ( wrapped_objects::template is_matched_v<A...> ) {
798 return this->call( std::forward<A>(args)... );
799 } else {
800 return call_default(std::forward<A>(args)...);
801 }
802 }
803 };
804
805 template<class...T>
806 class wrapped_objects<void, T...> : public wrapped_objects_base<T...> {
807 public:
808 using wrapped_objects_base<T...>::wrapped_objects_base;
809
810 template<class...A>
811 constexpr decltype(auto) operator() (A&&...args) const {
812 return
813 this->call(std::forward<A>(args)...);
814 }
815 };
816
817 /*
818 * This only has the job of creating a wrapped_objects.
819 * It is intended to be a short lived object.
820 */
821 template<class F>
822 class default_function {
823 F& functor_ref;
824 public:
825 constexpr default_function(F& f) : functor_ref(f) {}
826 default_function(default_function&&) = default;
827 default_function(const default_function&) = delete;
828
829 template<class...T>
830 constexpr wrapped_objects<F, T...> operator() (T&&...objs) const {
831 return {functor_ref, objs...};
832 }
833 };
834
835public:
836 /*
837 * The public methods are static because member_caller itself holds all its
838 * defining characteristics in its type.
839 */
840
845 template<class F>
846 static constexpr default_function<F> fallback(F&& f) { return f; }
847
851 template<class...T>
852 static constexpr wrapped_objects<void, T...> with(T&&...objs) {
853 return {objs...};
854 }
855
856 template<class...T>
857 constexpr auto operator() (T&&...objs) const { return with<T...>(objs...); }
858};
859
860
861
862
871
872
873
874
957template<class Access, member_value_copy CopyValue = MEMBER_COPY_AUTO>
959 static_assert(
960 (CopyValue == MEMBER_COPY_AUTO) ||
961 (CopyValue == MEMBER_COPY_ALWAYS) ||
962 (CopyValue == MEMBER_COPY_NEVER)
963 );
964private:
965 struct empty {
966 template<class F, class...A>
967 constexpr decltype(auto) get(F&& func, A&&...args) const {
968 return std::forward<F>(func)(std::forward<A>(args)...);
969 }
970
971 static constexpr bool has_member = false;
972
973 constexpr void get() const {
974 static_assert(
975 false,
976 "Can't get member that was not found in any object."
977 );
978 }
979 };
980
981 template<class T>
982 class wrapped_object_member {
983 using object_type = T;
984
985 // The actual type of the member, as declared in T's definition.
986 using member_type = typename Access::ugmisc::template member_type<T>;
987
988 using effective_member_type =
989 decltype(Access::ugmisc::get(std::declval<T&>()));
990
991 using deref_effective_member_type =
992 std::remove_reference_t<effective_member_type>;
993
994 static constexpr bool rvalue_object =
995 !std::is_lvalue_reference_v<object_type>;
996
997 static constexpr bool const_object =
998 std::is_const_v<object_type>;
999
1000 static constexpr bool volatile_object =
1001 std::is_volatile_v<object_type>;
1002
1003 static constexpr bool member_is_reference =
1004 std::is_lvalue_reference_v<member_type>;
1005
1006 static constexpr bool volatile_member =
1007 std::is_volatile_v<deref_effective_member_type>;
1008
1009 static constexpr bool const_member =
1010 std::is_const_v<deref_effective_member_type>;
1011
1012 static constexpr bool rvalue_member =
1013 (! member_is_reference) && rvalue_object;
1014
1015 /*
1016 * copy_member == true: the member value is copied into the wrapper,
1017 * and returned by copy from get().
1018 */
1019 static constexpr bool copy_member =
1020 (CopyValue == MEMBER_COPY_ALWAYS)
1021 || (
1022 (CopyValue != MEMBER_COPY_NEVER)
1023 && (!volatile_member)
1024 && (const_member || rvalue_member)
1025 && std::is_trivially_copyable_v< member_type >
1026 );
1027
1028 /*
1029 * return rvalue_member == true: a reference to the member is stored,
1030 * and an rvalue reference is returned from get().
1031 */
1032 static constexpr bool return_rvalue_member =
1033 (!copy_member) && rvalue_member;
1034
1035 static constexpr bool return_lvalue_member =
1036 (!return_rvalue_member || copy_member);
1037
1038 using member_store_type = std::conditional_t<
1039 copy_member,
1040 const std::remove_volatile_t<deref_effective_member_type>,
1041 effective_member_type
1042 >;
1043
1044 using member_return_type = std::conditional_t<
1045 copy_member,
1046 std::remove_const_t<member_store_type>,
1047 std::conditional_t<
1048 return_rvalue_member,
1049 deref_effective_member_type&&,
1050 deref_effective_member_type&
1051 >
1052 >;
1053
1054 // This may be a copy of the member's value where that is safe to do.
1055 // Otherwise it is a reference to the member.
1056 member_store_type member;
1057 public:
1058 static constexpr bool has_member = true;
1059
1060 constexpr wrapped_object_member( object_type& obj )
1061 : member( Access::ugmisc::get(obj) )
1062 {}
1063
1064 wrapped_object_member(const wrapped_object_member&) = default;
1065 wrapped_object_member(wrapped_object_member&&) = default;
1066
1067 template<class...A>
1068 constexpr member_return_type get(A&&...args) const { return member; }
1069 };
1070
1071 static constexpr empty find_ref() { return {}; }
1072
1073 template<class T1, class...T>
1074 static constexpr auto find_ref(T1&& obj, T&&...objs) {
1075 if constexpr ( Access::ugmisc::template has_member<T1> ) {
1076 return wrapped_object_member<T1>{ obj };
1077 } else {
1078 return find_ref(std::forward<T>(objs)...);
1079 }
1080 }
1081
1082public:
1083 /*
1084 * The public methods are static because member_value itself holds all its
1085 * defining characteristics in its type.
1086 */
1087
1091 template<class...T>
1092 static constexpr auto with(T&&...objs) {
1093 return find_ref(std::forward<T>(objs)...);
1094 }
1095
1096 template<class...T>
1097 constexpr auto operator() (T&&...objs) const { return with<T...>(objs...); }
1098
1112
1122
1132};
1133
1134
1135
1136
1138namespace member_ {
1143template< class Access, class TypeList > class member_type_access_traits {
1144 using all_types = TypeList;
1145 using normal_types =
1146 filter_type_list<member_::get_is_default_type, all_types, invert_test>;
1147 using default_types =
1148 filter_type_list<member_::get_is_default_type, all_types>;
1149
1150 static_assert( default_types::size <= 1 );
1151 static_assert( default_types::size + normal_types::size == all_types::size );
1152
1153 using access = Access;
1154
1155 template<bool Found, class U> struct result {
1156 static constexpr bool found = Found;
1157 using type = U;
1158 };
1159
1160 /*
1161 * This allows us to avoid instantiating type_list_member<0, seq> where seq
1162 * is empty.
1163 */
1164 template< class seq = normal_types >
1165 static constexpr auto find_type_pair() {
1166
1167 if constexpr ( seq::size == 0 ) {
1168 return result<false, void>{};
1169 } else {
1170 using first_type = type_list_member<0, seq>;
1171 if constexpr ( access::ugmisc::template has_member_type<first_type> ) {
1172 return result<
1173 true,
1174 typename access::ugmisc::template type<first_type>
1175 >{};
1176 } else {
1177 return find_type_pair< type_list_remove_prefix<1, seq> >();
1178 }
1179 }
1180 }
1181
1182 using result_t = decltype(find_type_pair());
1183
1184 /*
1185 * This allows us to avoid instantiating type_list_member<default_types>
1186 * when default_types is empty.
1187 */
1188 static constexpr auto find_default_type_pair() {
1189 if constexpr ( default_types::size ) {
1190 return result<true, type_list_member<0, default_types>>{};
1191 } else {
1192 return result<false, void>{};
1193 }
1194 }
1195
1196 using default_t = decltype(find_default_type_pair());
1197
1198
1199public:
1200 static constexpr bool has_member = result_t::found;
1201 static constexpr bool has_default = default_t::found;
1202 static constexpr bool has_type = has_member || has_default;
1203 using type = std::conditional_t<
1204 has_member,
1205 typename result_t::type,
1206 typename default_t::type
1207 >;
1208};
1209
1210
1211
1212
1217template<
1218 class Access,
1219 class TypeList,
1220 bool HasType = member_type_access_traits<Access, TypeList>::has_type
1221 >
1222struct member_type_access {
1223 static_assert( ! HasType, "There is a missing specialisation." );
1224 static constexpr bool has_member = false;
1225 static constexpr bool has_default = false;
1226 static constexpr bool has_type = false;
1227 // Don't declare type!
1228 using safe_type = void;
1229};
1230
1231
1232template<class Access, class TypeList>
1233struct member_type_access<Access, TypeList, true> {
1234 static constexpr bool has_member
1235 = member_type_access_traits<Access, TypeList>::has_member;
1236
1237 static constexpr bool has_default
1238 = member_type_access_traits<Access, TypeList>::has_default;
1239
1240 static constexpr bool has_type = true;
1241
1242 using type
1243 = typename member_type_access_traits<Access, TypeList>::type;
1244
1245 using safe_type = type;
1246};
1247
1248
1249
1250
1251template<class Access, class...T>
1252class static_member_value_base {
1253 template<class U> struct access {
1254 using type = U;
1255 static constexpr bool has_member = Access::ugmisc::template has_static_member<U>;
1256 static constexpr auto& get() { return Access::ugmisc::template static_get<U>(); }
1257 };
1258
1259 struct void_wrapper {
1260 using type = void;
1261 };
1262
1263 template<bool Found, class Type=void_wrapper>
1264 struct result {
1265 using type = Type;
1266 static constexpr bool found = Found;
1267 };
1268
1269 using accessor_types = flatten_apply_each_class<access, T...>;
1270
1271 template<class accessors = accessor_types>
1272 static constexpr auto find_matching_type() {
1273 if constexpr ( accessors::size == 0 ) {
1274 return result<false>{};
1275 } else {
1276 using first_type = type_list_member<0, accessors>;
1277 if constexpr ( first_type::has_member ) {
1278 return result<true, first_type>{};
1279 } else {
1280 return find_matching_type<type_list_remove_prefix<1, accessors>>();
1281 }
1282 }
1283 }
1284
1285 using result_type = decltype(find_matching_type());
1286 using getter_type = typename result_type::type;
1287
1288public:
1289 static constexpr bool has_member = result_type::found;
1290
1291 template<class F, class...A>
1292 static constexpr decltype(auto) get(F&& default_get, A&&...args) {
1293 if constexpr ( has_member ) {
1294 return getter_type::get();
1295 } else {
1296 return default_get(std::forward<A>(args)...);
1297 }
1298 }
1299
1300 static constexpr auto& get() { return getter_type::get(); }
1301
1302 using safe_matched_type = typename getter_type::type;
1303};
1304
1305
1306template<bool WithType, class Access, class...T>
1307struct static_member_value;
1308
1309template<class Access, class...T>
1310struct static_member_value<true, Access, T...>
1311: public static_member_value_base<Access, T...>
1312{
1313 using matched_type =
1314 typename static_member_value_base<Access, T...>::safe_matched_type;
1315};
1316
1317template<class Access, class...T>
1318struct static_member_value<false, Access, T...>
1319: public static_member_value_base<Access, T...>
1320{ };
1321
1322
1323template<class Access, class...T>
1324using static_member_value_t =
1325 static_member_value<
1326 static_member_value_base<Access, T...>::has_member,
1327 Access, T...
1328 >;
1329
1330
1331} /* member_ (::ugmisc::member_) */
1333
1334
1335
1336#ifndef UGMISC_DOCS
1337template< class Access, class...T > class member_type_access
1338: public member_::member_type_access<Access, flatten_t<T...>>
1339{
1340};
1341#else
1342
1378template< class Access, class...T > struct member_type_access {
1383 static constexpr bool has_member = ???;
1384
1390 static constexpr bool has_default = ???;
1391
1396 static constexpr bool has_type = has_member || has_default;
1397
1409 using type = ???;
1410
1415 using safe_type = ???;
1416};
1417#endif
1418
1419
1420
1421
1459template<class Access, class...T>
1460struct static_member_value : public member_::static_member_value_t<Access, T...>
1461{
1462#ifdef UGMISC_DOCS
1467 static constexpr bool has_member = ???;
1468
1479 template<class F, class...A>
1480 static constexpr decltype(auto) get(F&& default_get, A&&...args);
1481
1487 static constexpr auto& get() { return getter_type::get(); }
1488
1496
1502 using matched_type = ???;
1503#endif
1504};
1505
1506
1507
1508
1509}
1510#endif /* UGMISC_MEMBER_HPP */
member_value_copy
Definition member.hpp:866
@ MEMBER_COPY_NEVER
Always take a reference to the original object.
Definition member.hpp:868
@ MEMBER_COPY_AUTO
Default. Copy value if safe and trivial to do so.
Definition member.hpp:867
@ MEMBER_COPY_ALWAYS
Always copy the value.
Definition member.hpp:869
Definition member.hpp:326
Definition member.hpp:666
static constexpr wrapped_objects< void, T... > with(T &&...objs)
Definition member.hpp:852
static constexpr default_function< F > fallback(F &&f)
Definition member.hpp:846
Definition member.hpp:1378
??? safe_type
Definition member.hpp:1415
static constexpr bool has_member
Definition member.hpp:1383
static constexpr bool has_default
Definition member.hpp:1390
??? type
Definition member.hpp:1409
static constexpr bool has_type
Definition member.hpp:1396
Definition member.hpp:958
static constexpr auto with(T &&...objs)
Definition member.hpp:1092
static constexpr member_value< Access, MEMBER_COPY_AUTO > copy_auto
Definition member.hpp:1111
static constexpr member_value< Access, MEMBER_COPY_ALWAYS > copy_always
Definition member.hpp:1121
static constexpr member_value< Access, MEMBER_COPY_NEVER > copy_never
Definition member.hpp:1131
Definition member.hpp:497
constexpr decltype(auto) operator()(Args &&...args) const
Definition member.hpp:583
static constexpr member_::fallback_caller< static_member_caller, std::remove_reference_t< F > > fallback(F &&functor)
Definition member.hpp:595
static constexpr bool is_matched(Args &&...)
Definition member.hpp:537
static matched_type< Args... > declval_matched(Args &&...) noexcept
static constexpr bool is_matched_v
Definition member.hpp:530
static constexpr decltype(auto) call(Args &&...args)
Definition member.hpp:568
typename caller< void, types_list, Args... >::type matched_type
Definition member.hpp:546
static safe_matched_type< Args... > safe_declval_matched(Args &&...) noexcept
Definition member.hpp:1461
static constexpr decltype(auto) get(F &&default_get, A &&...args)
??? safe_matched_type
Definition member.hpp:1495
??? matched_type
Definition member.hpp:1502
static constexpr auto & get()
Definition member.hpp:1487
static constexpr bool has_member
Definition member.hpp:1467
Encapsulates a list of types.
Definition typelist.hpp:811
Lists of types which may be used in some of the ugmisc templates where a single type would usually be...
typename flatten< T... >::type flatten_t
Converts the template parameters into a type_list.
Definition typelist.hpp:200
type_list_apply_each_class< F, flatten_t< T... > > flatten_apply_each_class
Definition typelist.hpp:372
typename typelist_::get_type_list_member< I, T >::type type_list_member
Definition typelist.hpp:172