24#ifndef UGMISC_MEMBER_HPP
25#define UGMISC_MEMBER_HPP
166#define UGMISC_DECL_MEMBER_ACCESS(TNAME, NAME) \
168 struct ugmisc_priv { \
171 template<class T, class, class...A> \
172 struct static_caller { \
173 static constexpr bool is_callable = false; \
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; \
180 static constexpr decltype(auto) call(A...args) { \
181 return T::NAME(std::forward<A>(args)...); \
187 template<class T, class, class...A> \
189 static constexpr bool is_callable = false; \
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; \
196 static constexpr decltype(auto) call(T& obj, A...args) { \
197 return std::forward<T>(obj).NAME(std::forward<A>(args)...); \
203 template<class T, class=void> \
204 struct static_member { \
205 static constexpr bool has_member = false; \
209 struct static_member<T, std::void_t<decltype(T::NAME)>> { \
210 static constexpr bool has_member = true; \
212 static constexpr auto& get() { \
219 template<class T, class=void> \
221 static constexpr bool has_member = false; \
225 struct member<T, std::void_t<decltype(std::declval<T>().NAME)>> { \
226 static constexpr bool has_member = true; \
228 static constexpr auto& get(T& obj) { \
232 using member_type = decltype(std::declval<std::remove_reference_t<T>>().NAME); \
236 template< class T, class=void > struct GetType { \
237 static constexpr bool has_member_type = false; \
238 using safe_type = void; \
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; \
251 template<class T, class...A> static constexpr bool is_static_callable = \
252 ugmisc_priv::static_caller<T, void, A...>::is_callable; \
254 template<class T, class...A> \
255 static constexpr auto static_call(A&&...args) \
257 ugmisc_priv::static_caller<T, void, A...>::call( \
258 std::forward<A>(args)... \
261 return ugmisc_priv::static_caller<T, void, A...>::call( \
262 std::forward<A>(args)... \
267 template<class T, class...A> static constexpr bool is_callable = \
268 ugmisc_priv::caller<T, void, A...>::is_callable; \
270 template<class T, class...A> \
271 static constexpr auto call(T& obj, A&&...args) \
273 ugmisc_priv::caller<T, void, A...>::call( \
275 std::forward<A>(args)... \
278 return ugmisc_priv::caller<T, void, A...>::call( \
280 std::forward<A>(args)... \
285 template< class T > \
286 static constexpr bool has_static_member \
287 = ugmisc_priv::static_member<T>::has_member; \
289 static constexpr auto& static_get() { \
290 return ugmisc_priv::static_member<T>::get(); \
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; \
300 static constexpr auto& get(T&& obj) { \
301 return ugmisc_priv::member<T>::get(obj); \
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; \
340struct get_is_default_type :
public std::false_type {};
343struct get_is_default_type< default_type<T> > :
public std::true_type {};
346struct get_is_not_default_type {
348 static constexpr bool value = !get_is_default_type<T>::value;
351template<
class T>
static inline bool is_default_type =
352 get_is_default_type<T>::value;
371template<
class StaticCaller,
class Functor>
372class fallback_caller {
379 template<
class Dummy,
class...T>
380 constexpr auto forward(Dummy*, T&&...args)
const
381 ->
decltype(m_functor(std::forward<T>(args)...))
383 return m_functor(std::forward<T>(args)...);
386 template<
class Dummy,
class...T>
387 constexpr decltype(
auto) forward(Dummy, T&&...args)
const {
393 constexpr fallback_caller(
const Functor& f) : m_functor(f) {}
394 constexpr fallback_caller(Functor&& f) : m_functor(std::move(f)) {}
396 fallback_caller(fallback_caller&&) =
default;
397 fallback_caller(
const fallback_caller&) =
delete;
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)...);
404 auto dummy = (
int*)
nullptr;
405 return forward(dummy, std::forward<T>(args)...);
410 constexpr decltype(
auto)
operator()(T&&...args)
const {
411 return call(std::forward<T>(args)...);
416template<
class Access,
class T,
class...A>
417inline constexpr bool is_static_callable_v =
418 Access::ugmisc::template is_static_callable<T, A...>;
421template<
class Access,
class T,
class...A>
422constexpr bool is_static_callable(A&&...) {
423 return is_static_callable_v<Access, T, A...>;
496template<
class Access,
class...T>
499 template<
class V,
class List,
class...Args>
501 :
public caller<V, type_list_remove_prefix<1, List>, Args...> {
504 template<
class...Args>
struct caller<void,
type_list<>, Args...> {
505 static constexpr bool is_callable =
false;
506 using safe_type = void;
509 template<
class List,
class...Args>
511 std::enable_if_t< member_::is_static_callable_v<Access, type_list_member<0, List>, Args...>>,
516 static constexpr bool is_callable =
true;
518 using safe_type = void;
529 template<
class...Args>
531 caller<void, types_list, Args...>::is_callable;
536 template<
class...Args>
545 template<
class...Args>
554 template<
class...Args>
555 using safe_matched_type =
556 typename caller<void, types_list, Args...>::safe_type;
567 template<
class...Args>
568 static constexpr decltype(
auto)
call(Args&&...args) {
572 "None of the types is callable with these argument types."
574 return Access::ugmisc::template static_call<type>(std::forward<Args>(args)...);
582 template<
class...Args>
583 constexpr decltype(
auto)
operator()(Args&&...args)
const {
584 return call(std::forward<Args>(args)...);
594 member_::fallback_caller<static_member_caller, std::remove_reference_t<F>>
596 return std::forward<F>(functor);
603 template<
class...Args>
610 template<class...Args>
618 template<class...Args>
624 template<class...Args>
665template<class Access>
676 struct wrapped_objects_base {
680 "A specialisation should have been used instead of this template."
683 template<
class...A>
static constexpr bool is_matched_v =
false;
684 template<
class...A>
static constexpr bool is_matched(A&&...) {
688 wrapped_objects_base() =
default;
689 wrapped_objects_base(
const wrapped_objects_base&) =
default;
692 constexpr void call(A&&...)
const {
693 static_assert(
false,
"There are no more objects to call.");
696 static constexpr bool safe_refs =
true;
699 static constexpr bool matched_here =
false;
702 template<
class T1,
class...T>
703 struct wrapped_objects_base<T1, T...> :
public wrapped_objects_base<T...>
709 static constexpr bool safe_refs =
710 std::is_lvalue_reference_v<T1> &&
711 wrapped_objects_base<T...>::safe_refs;
715 static constexpr bool matched_here =
716 Access::ugmisc::template is_callable<T1, A...>;
719 constexpr decltype(
auto) call(A&&...args)
const {
720 if constexpr ( matched_here<A...> ) {
721 return Access::ugmisc::template call(
723 std::forward<A>(args)...
726 return this->wrapped_objects_base<T...>::call(std::forward<A>(args)...);
731 constexpr wrapped_objects_base(T1& obj, T&...t)
732 : wrapped_objects_base<T...>(t...), obj_ref(obj)
735 wrapped_objects_base(wrapped_objects_base&&) =
default;
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)
743 "Can't copy a member_caller::wrapped_objects if the "
744 "referenced objects aren't all lvalues."
749 static constexpr bool is_matched_v =
750 matched_here<A...> ||
751 wrapped_objects_base<T...>::template matched_here<A...>;
754 static constexpr bool is_matched(A&&...) {
755 return is_matched_v<A...>;
763 template<
class F,
class...T>
764 class wrapped_objects :
public wrapped_objects<void, T...> {
766 using wrapped_objects<void, T...>::wrapped_objects;
768 template<
class,
class...A>
struct forwarder {
769 static constexpr decltype(
auto) call(F& f, A&...args) {
776 std::void_t< decltype(std::declval<F>()(std::declval<A>()...)) >,
780 static constexpr decltype(
auto) call(F& f, A&...args) {
781 return f(std::forward<A>(args)...);
786 constexpr decltype(
auto) call_default(A&&...args)
const {
787 return forwarder<void, A...>::call(functor, args...);
791 constexpr wrapped_objects(F& f, T...t)
792 : wrapped_objects<void, T...>(t...), functor(f)
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)... );
800 return call_default(std::forward<A>(args)...);
806 class wrapped_objects<void, T...> :
public wrapped_objects_base<T...> {
808 using wrapped_objects_base<T...>::wrapped_objects_base;
811 constexpr decltype(
auto)
operator() (A&&...args)
const {
813 this->call(std::forward<A>(args)...);
822 class default_function {
825 constexpr default_function(F& f) : functor_ref(f) {}
826 default_function(default_function&&) =
default;
827 default_function(
const default_function&) =
delete;
830 constexpr wrapped_objects<F, T...> operator() (T&&...objs)
const {
831 return {functor_ref, objs...};
846 static constexpr default_function<F>
fallback(F&& f) {
return f; }
852 static constexpr wrapped_objects<void, T...>
with(T&&...objs) {
857 constexpr auto operator() (T&&...objs)
const {
return with<T...>(objs...); }
957template<
class Access, member_value_copy CopyValue = MEMBER_COPY_AUTO>
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)...);
971 static constexpr bool has_member =
false;
973 constexpr void get()
const {
976 "Can't get member that was not found in any object."
982 class wrapped_object_member {
983 using object_type = T;
986 using member_type =
typename Access::ugmisc::template member_type<T>;
988 using effective_member_type =
989 decltype(Access::ugmisc::get(std::declval<T&>()));
991 using deref_effective_member_type =
992 std::remove_reference_t<effective_member_type>;
994 static constexpr bool rvalue_object =
995 !std::is_lvalue_reference_v<object_type>;
997 static constexpr bool const_object =
998 std::is_const_v<object_type>;
1000 static constexpr bool volatile_object =
1001 std::is_volatile_v<object_type>;
1003 static constexpr bool member_is_reference =
1004 std::is_lvalue_reference_v<member_type>;
1006 static constexpr bool volatile_member =
1007 std::is_volatile_v<deref_effective_member_type>;
1009 static constexpr bool const_member =
1010 std::is_const_v<deref_effective_member_type>;
1012 static constexpr bool rvalue_member =
1013 (! member_is_reference) && rvalue_object;
1019 static constexpr bool copy_member =
1023 && (!volatile_member)
1024 && (const_member || rvalue_member)
1025 && std::is_trivially_copyable_v< member_type >
1032 static constexpr bool return_rvalue_member =
1033 (!copy_member) && rvalue_member;
1035 static constexpr bool return_lvalue_member =
1036 (!return_rvalue_member || copy_member);
1038 using member_store_type = std::conditional_t<
1040 const std::remove_volatile_t<deref_effective_member_type>,
1041 effective_member_type
1044 using member_return_type = std::conditional_t<
1046 std::remove_const_t<member_store_type>,
1048 return_rvalue_member,
1049 deref_effective_member_type&&,
1050 deref_effective_member_type&
1056 member_store_type member;
1058 static constexpr bool has_member =
true;
1060 constexpr wrapped_object_member( object_type& obj )
1061 : member( Access::ugmisc::get(obj) )
1064 wrapped_object_member(
const wrapped_object_member&) =
default;
1065 wrapped_object_member(wrapped_object_member&&) =
default;
1068 constexpr member_return_type get(A&&...args)
const {
return member; }
1071 static constexpr empty find_ref() {
return {}; }
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 };
1078 return find_ref(std::forward<T>(objs)...);
1092 static constexpr auto with(T&&...objs) {
1093 return find_ref(std::forward<T>(objs)...);
1097 constexpr auto operator() (T&&...objs)
const {
return with<T...>(objs...); }
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>;
1150 static_assert( default_types::size <= 1 );
1151 static_assert( default_types::size + normal_types::size == all_types::size );
1153 using access = Access;
1155 template<
bool Found,
class U>
struct result {
1156 static constexpr bool found = Found;
1164 template<
class seq = normal_types >
1165 static constexpr auto find_type_pair() {
1167 if constexpr ( seq::size == 0 ) {
1168 return result<false, void>{};
1170 using first_type = type_list_member<0, seq>;
1171 if constexpr ( access::ugmisc::template has_member_type<first_type> ) {
1174 typename access::ugmisc::template type<first_type>
1177 return find_type_pair< type_list_remove_prefix<1, seq> >();
1182 using result_t =
decltype(find_type_pair());
1188 static constexpr auto find_default_type_pair() {
1189 if constexpr ( default_types::size ) {
1190 return result<true, type_list_member<0, default_types>>{};
1192 return result<false, void>{};
1196 using default_t =
decltype(find_default_type_pair());
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<
1205 typename result_t::type,
1206 typename default_t::type
1220 bool HasType = member_type_access_traits<Access, TypeList>::has_type
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;
1228 using safe_type = void;
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;
1237 static constexpr bool has_default
1238 = member_type_access_traits<Access, TypeList>::has_default;
1240 static constexpr bool has_type =
true;
1243 =
typename member_type_access_traits<Access, TypeList>::type;
1245 using safe_type = type;
1251template<
class Access,
class...T>
1252class static_member_value_base {
1253 template<
class U>
struct access {
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>(); }
1259 struct void_wrapper {
1263 template<
bool Found,
class Type=
void_wrapper>
1266 static constexpr bool found = Found;
1271 template<
class accessors = accessor_types>
1272 static constexpr auto find_matching_type() {
1273 if constexpr ( accessors::size == 0 ) {
1274 return result<false>{};
1276 using first_type = type_list_member<0, accessors>;
1277 if constexpr ( first_type::has_member ) {
1278 return result<true, first_type>{};
1280 return find_matching_type<type_list_remove_prefix<1, accessors>>();
1285 using result_type =
decltype(find_matching_type());
1286 using getter_type =
typename result_type::type;
1289 static constexpr bool has_member = result_type::found;
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();
1296 return default_get(std::forward<A>(args)...);
1300 static constexpr auto& get() {
return getter_type::get(); }
1302 using safe_matched_type =
typename getter_type::type;
1306template<
bool WithType,
class Access,
class...T>
1307struct static_member_value;
1309template<
class Access,
class...T>
1310struct static_member_value<true, Access, T...>
1311:
public static_member_value_base<Access, T...>
1313 using matched_type =
1314 typename static_member_value_base<Access, T...>::safe_matched_type;
1317template<
class Access,
class...T>
1318struct static_member_value<false, Access, T...>
1319:
public static_member_value_base<Access, T...>
1323template<
class Access,
class...T>
1324using static_member_value_t =
1325 static_member_value<
1326 static_member_value_base<Access, T...>::has_member,
1337template<
class Access,
class...T >
class member_type_access
1338:
public member_::member_type_access<Access, flatten_t<T...>>
1459template<
class Access,
class...T>
1479 template<
class F,
class...A>
1480 static constexpr decltype(
auto)
get(F&& default_get, A&&...args);
1487 static constexpr auto&
get() {
return getter_type::get(); }
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