5#ifndef UGMISC_MEMBER_HPP
6#define UGMISC_MEMBER_HPP
150#define UGMISC_DECL_MEMBER_ACCESS(TNAME, NAME) \
152 struct ugmisc_priv { \
155 template<class ugmisc__T, class, class...ugmisc__A> \
156 struct static_caller_as_function { \
157 static constexpr bool is_callable = false; \
160 template<class ugmisc__T, class...ugmisc__A> \
161 struct static_caller_as_function<ugmisc__T, std::void_t<decltype(ugmisc__T::NAME(std::declval<ugmisc__A>()...))>, ugmisc__A...> { \
162 static constexpr bool is_callable = true; \
164 static constexpr decltype(auto) call(ugmisc__A...args) { \
165 return ugmisc__T::NAME(std::forward<ugmisc__A>(args)...); \
169 template<class ugmisc__T, bool, class...ugmisc__A> \
170 struct static_caller_as_invoke { \
171 static constexpr bool is_callable = false; \
174 template<class ugmisc__T, class...ugmisc__A> \
175 struct static_caller_as_invoke<ugmisc__T, std::is_invocable_v<decltype((ugmisc__T::NAME)), ugmisc__A...>, ugmisc__A...> { \
176 static constexpr bool is_callable = true; \
178 static constexpr decltype(auto) call(ugmisc__A...args) { \
179 return std::invoke(ugmisc__T::NAME, std::forward<ugmisc__A>(args)...); \
183 template<class ugmisc__T, class...ugmisc__A> \
184 using static_caller = std::conditional_t< \
185 static_caller_as_function<ugmisc__T, void, ugmisc__A...>::is_callable, \
186 static_caller_as_function<ugmisc__T, void, ugmisc__A...>, \
187 static_caller_as_invoke<ugmisc__T, true, ugmisc__A...> \
192 template<class ugmisc__T, class, class...ugmisc__A> \
193 struct caller_as_method { \
194 static constexpr bool is_callable = false; \
197 template<class ugmisc__T, class...ugmisc__A> \
198 struct caller_as_method<ugmisc__T, std::void_t<decltype(std::declval<ugmisc__T>().NAME(std::declval<ugmisc__A>()...))>, ugmisc__A...> { \
199 static constexpr bool is_callable = true; \
201 static constexpr decltype(auto) call(ugmisc__T& obj, ugmisc__A...args) { \
202 return std::forward<ugmisc__T>(obj).NAME(std::forward<ugmisc__A>(args)...); \
206 template<class ugmisc__T, bool I, class...ugmisc__A> \
207 struct caller_as_invoke { \
208 static constexpr bool is_callable = false; \
211 template<class ugmisc__T, class...ugmisc__A> \
212 struct caller_as_invoke<ugmisc__T, \
213 std::is_invocable_v<decltype(std::declval<ugmisc__T>().NAME), ugmisc__A...>, \
217 static constexpr bool is_callable = true; \
218 static constexpr decltype(auto) call(ugmisc__T& obj, ugmisc__A...args) { \
219 return std::invoke(std::forward<ugmisc__T>(obj).NAME, std::forward<ugmisc__A>(args)...); \
223 template<class ugmisc__T, class...ugmisc__A> \
224 using caller = std::conditional_t< \
225 caller_as_method<ugmisc__T, void, ugmisc__A...>::is_callable, \
226 caller_as_method<ugmisc__T, void, ugmisc__A...>, \
227 caller_as_invoke<ugmisc__T, true, ugmisc__A...> \
231 template<class ugmisc__T, class=void> \
232 struct static_member { \
233 static constexpr bool has_member = false; \
236 template<class ugmisc__T> \
237 struct static_member<ugmisc__T, std::void_t<decltype(ugmisc__T::NAME)>> { \
238 static constexpr bool has_member = true; \
240 static constexpr auto& get() { \
241 return ugmisc__T::NAME; \
247 template<class ugmisc__T, class=void> \
249 static constexpr bool has_member = false; \
252 template<class ugmisc__T> \
253 struct member<ugmisc__T, std::void_t<decltype(std::declval<ugmisc__T>().NAME)>> { \
254 static constexpr bool has_member = true; \
256 static constexpr auto& get(ugmisc__T& obj) { \
260 using member_type = decltype(std::declval<std::remove_reference_t<ugmisc__T>>().NAME); \
264 template< class ugmisc__T, class=void > struct GetType { \
265 static constexpr bool has_member_type = false; \
266 using safe_type = void; \
269 template< class ugmisc__T > struct GetType< ugmisc__T, std::void_t< typename ugmisc__T::NAME > > { \
270 static constexpr bool has_member_type = true; \
271 using safe_type = typename ugmisc__T::NAME; \
272 using type = typename ugmisc__T::NAME; \
279 template<class ugmisc__T, class...ugmisc__A> static constexpr bool is_static_callable = \
280 ugmisc_priv::template static_caller<ugmisc__T, ugmisc__A...>::is_callable; \
282 template<class ugmisc__T, class...ugmisc__A> \
283 static constexpr auto static_call(ugmisc__A&&...args) \
285 ugmisc_priv::template static_caller<ugmisc__T, ugmisc__A...>::call( \
286 std::forward<ugmisc__A>(args)... \
289 return ugmisc_priv::template static_caller<ugmisc__T, ugmisc__A...>::call( \
290 std::forward<ugmisc__A>(args)... \
295 template<class ugmisc__T, class...ugmisc__A> static constexpr bool is_callable = \
296 ugmisc_priv::template caller<ugmisc__T, ugmisc__A...>::is_callable; \
298 template<class ugmisc__T, class...ugmisc__A> \
299 static constexpr auto call(ugmisc__T& obj, ugmisc__A&&...args) \
301 ugmisc_priv::template caller<ugmisc__T, ugmisc__A...>::call( \
303 std::forward<ugmisc__A>(args)... \
306 return ugmisc_priv::template caller<ugmisc__T, ugmisc__A...>::call( \
308 std::forward<ugmisc__A>(args)... \
313 template< class ugmisc__T > \
314 static constexpr bool has_static_member \
315 = ugmisc_priv::template static_member<ugmisc__T>::has_member; \
316 template< class ugmisc__T> \
317 static constexpr auto& static_get() { \
318 return ugmisc_priv::template static_member<ugmisc__T>::get(); \
322 template< class ugmisc__T > \
323 static constexpr bool has_member \
324 = ugmisc_priv::template member<ugmisc__T>::has_member; \
325 template< class ugmisc__T > \
326 using member_type = typename ugmisc_priv::member<ugmisc__T>::member_type; \
327 template< class ugmisc__T> \
328 static constexpr auto& get(ugmisc__T&& obj) { \
329 return ugmisc_priv::template member<ugmisc__T>::get(obj); \
334 template< class ugmisc__T > using type = typename ugmisc_priv::GetType<ugmisc__T>::type; \
335 template< class ugmisc__T > using safe_type = \
336 typename ugmisc_priv::GetType<ugmisc__T>::safe_type; \
337 template< class ugmisc__T > static constexpr bool has_member_type = \
338 ugmisc_priv::template GetType<ugmisc__T>::has_member_type; \
365template<
class V,
class F,
class...A>
366struct can_simple_call :
public std::false_type {};
368template<
class F,
class...A>
369struct can_simple_call< std::void_t<decltype(std::declval<F>()(std::declval<A>()...))>, F, A...> :
public std::true_type {};
371template<
class F,
class...A>
372constexpr bool can_simple_call_v = can_simple_call<void, F, A...>::value;
379template<
class F,
class...A>
380constexpr auto invoke(F&& func, A&&...args)
381-> std::invoke_result_t<F, A...>
385 return std::invoke(std::forward<F>(func), std::forward<A>(args)...);
389 if constexpr ( can_simple_call_v<F, A...> ) {
390 return std::forward<F>(func)(std::forward<A>(args)...);
392 return std::invoke(std::forward<F>(func), std::forward<A>(args)...);
399struct get_is_default_type :
public std::false_type {};
402struct get_is_default_type< default_type<T> > :
public std::true_type {};
405struct get_is_not_default_type {
407 static constexpr bool value = !get_is_default_type<T>::value;
410template<
class T>
static inline bool is_default_type =
411 get_is_default_type<T>::value;
436template<
class StaticCaller,
class Functor>
437class fallback_caller {
444 template<
class Dummy,
class...T>
445 constexpr auto forward(Dummy*, T&&...args)
const
446 ->
decltype(invoke(m_functor, std::forward<T>(args)...))
448 return invoke(m_functor, std::forward<T>(args)...);
451 template<
class Dummy,
class...T>
452 constexpr decltype(
auto) forward(Dummy, T&&...args)
const {
458 constexpr fallback_caller(Functor f) : m_functor(std::forward<Functor>(f)) {}
460 fallback_caller(fallback_caller&&) =
default;
461 fallback_caller(
const fallback_caller&) =
delete;
464 constexpr decltype(
auto) call(T&&...args)
const {
465 if constexpr ( StaticCaller::template is_matched_v<T...> ) {
466 return StaticCaller::call(std::forward<T>(args)...);
468 auto dummy = (
int*)
nullptr;
469 return forward(dummy, std::forward<T>(args)...);
474 constexpr decltype(
auto)
operator()(T&&...args)
const {
475 return call(std::forward<T>(args)...);
480template<
class Access,
class T,
class...A>
481inline constexpr bool is_static_callable_v =
482 Access::ugmisc::template is_static_callable<T, A...>;
485template<
class Access,
class T,
class...A>
486constexpr bool is_static_callable(A&&...) {
487 return is_static_callable_v<Access, T, A...>;
572template<
class Access,
class...T>
575 template<
class V,
class List,
class...Args>
577 :
public caller<V, type_list_remove_prefix<1, List>, Args...> {
580 template<
class...Args>
struct caller<void,
type_list<>, Args...> {
581 static constexpr bool is_callable =
false;
582 using safe_type = void;
585 template<
class List,
class...Args>
587 std::enable_if_t< member_::is_static_callable_v<Access, type_list_member<0, List>, Args...>>,
592 static constexpr bool is_callable =
true;
594 using safe_type = void;
605 template<
class...Args>
607 caller<void, types_list, Args...>::is_callable;
612 template<
class...Args>
621 template<
class...Args>
630 template<
class...Args>
631 using safe_matched_type =
632 typename caller<void, types_list, Args...>::safe_type;
643 template<
class...Args>
644 static constexpr decltype(
auto)
call(Args&&...args) {
648 "None of the types is callable with these argument types."
650 return Access::ugmisc::template static_call<type>(std::forward<Args>(args)...);
658 template<
class...Args>
659 constexpr decltype(
auto)
operator()(Args&&...args)
const {
660 return call(std::forward<Args>(args)...);
670 member_::fallback_caller<static_member_caller, F>
679 template<
class...Args>
686 template<class...Args>
694 template<class...Args>
700 template<class...Args>
751template<class Access>
762 struct wrapped_objects_base {
766 "A specialisation should have been used instead of this template."
769 template<
class...A>
static constexpr bool is_matched_v =
false;
770 template<
class...A>
static constexpr bool is_matched(A&&...) {
774 wrapped_objects_base() =
default;
775 wrapped_objects_base(
const wrapped_objects_base&) =
default;
778 constexpr void call(A&&...)
const {
779 static_assert(
false,
"There are no more objects to call.");
782 static constexpr bool safe_refs =
true;
785 static constexpr bool matched_here =
false;
788 template<
class T1,
class...T>
789 struct wrapped_objects_base<T1, T...> :
public wrapped_objects_base<T...>
795 static constexpr bool safe_refs =
796 std::is_lvalue_reference_v<T1> &&
797 wrapped_objects_base<T...>::safe_refs;
801 static constexpr bool matched_here =
802 Access::ugmisc::template is_callable<T1, A...>;
805 constexpr decltype(
auto) call(A&&...args)
const {
806 if constexpr ( matched_here<A...> ) {
807 return Access::ugmisc::template call(
809 std::forward<A>(args)...
812 return this->wrapped_objects_base<T...>::call(std::forward<A>(args)...);
817 constexpr wrapped_objects_base(T1& obj, T&...t)
818 : wrapped_objects_base<T...>(t...), obj_ref(obj)
821 wrapped_objects_base(wrapped_objects_base&&) =
default;
823 constexpr wrapped_objects_base(
const wrapped_objects_base& other)
824 : wrapped_objects_base<T...>((wrapped_objects_base<T...>)other),
825 obj_ref(other.obj_ref)
829 "Can't copy a member_caller::wrapped_objects if the "
830 "referenced objects aren't all lvalues."
835 static constexpr bool is_matched_v =
836 matched_here<A...> ||
837 wrapped_objects_base<T...>::template matched_here<A...>;
840 static constexpr bool is_matched(A&&...) {
841 return is_matched_v<A...>;
849 template<
class F,
class...T>
850 class wrapped_objects :
public wrapped_objects<void, T...> {
852 using wrapped_objects<void, T...>::wrapped_objects;
854 template<
class,
class...A>
struct forwarder {
855 static constexpr decltype(
auto) call(F& f, A&...args) {
862 std::void_t< decltype(member_::invoke(std::declval<F&>(), std::declval<A>()...)) >,
866 static constexpr decltype(
auto) call(F& f, A&...args) {
867 return member_::invoke(f, std::forward<A>(args)...);
872 constexpr decltype(
auto) call_default(A&&...args) {
873 return forwarder<void, A...>::call(functor, args...);
877 constexpr wrapped_objects(F f, T...t)
878 : wrapped_objects<void, T...>(t...),
879 functor(std::forward<F>(f))
883 constexpr decltype(
auto)
operator()(A&&...args) {
884 if constexpr ( wrapped_objects::template is_matched_v<A...> ) {
885 return this->call( std::forward<A>(args)... );
887 return call_default(std::forward<A>(args)...);
893 class wrapped_objects<void, T...> :
public wrapped_objects_base<T...> {
895 using wrapped_objects_base<T...>::wrapped_objects_base;
898 constexpr decltype(
auto)
operator() (A&&...args)
const {
900 this->call(std::forward<A>(args)...);
911 class default_function {
914 constexpr default_function(F f) : functor(std::forward<F>(f)) {}
915 default_function(default_function&&) =
default;
916 default_function(
const default_function&) =
delete;
919 constexpr wrapped_objects<F, T...> operator() (T&&...objs)
const {
920 return {functor, objs...};
935 static constexpr default_function<F>
fallback(F&& f) {
return f; }
941 static constexpr wrapped_objects<void, T...>
with(T&&...objs) {
946 constexpr auto operator() (T&&...objs)
const {
return with<T...>(objs...); }
1051template<
class Access, member_value_copy CopyValue = MEMBER_COPY_AUTO>
1060 template<
class F,
class...A>
1061 constexpr decltype(
auto) get(F&& func, A&&...args)
const {
1062 return member_::invoke(
1063 std::forward<F>(func), std::forward<A>(args)...
1067 static constexpr bool has_member =
false;
1069 constexpr void get()
const {
1072 "Can't get member that was not found in any object."
1077 constexpr decltype(
auto)
operator() (T&&...args)
const {
1078 return get(std::forward<T>(args)...);
1083 class wrapped_object_member {
1084 using object_type = T;
1087 using member_type =
typename Access::ugmisc::template member_type<T>;
1089 using effective_member_type =
1090 decltype(Access::ugmisc::get(std::declval<T&>()));
1092 using deref_effective_member_type =
1093 std::remove_reference_t<effective_member_type>;
1095 static constexpr bool rvalue_object =
1096 !std::is_lvalue_reference_v<object_type>;
1098 static constexpr bool const_object =
1099 std::is_const_v<object_type>;
1101 static constexpr bool volatile_object =
1102 std::is_volatile_v<object_type>;
1104 static constexpr bool member_is_reference =
1105 std::is_lvalue_reference_v<member_type>;
1107 static constexpr bool volatile_member =
1108 std::is_volatile_v<deref_effective_member_type>;
1110 static constexpr bool const_member =
1111 std::is_const_v<deref_effective_member_type>;
1113 static constexpr bool rvalue_member =
1114 (! member_is_reference) && rvalue_object;
1120 static constexpr bool copy_member =
1124 && (!volatile_member)
1125 && (const_member || rvalue_member)
1126 && std::is_trivially_copyable_v< member_type >
1133 static constexpr bool return_rvalue_member =
1134 (!copy_member) && rvalue_member;
1136 static constexpr bool return_lvalue_member =
1137 (!return_rvalue_member || copy_member);
1139 using member_store_type = std::conditional_t<
1141 const std::remove_volatile_t<deref_effective_member_type>,
1142 effective_member_type
1145 using member_return_type = std::conditional_t<
1147 std::remove_const_t<member_store_type>,
1149 return_rvalue_member,
1150 deref_effective_member_type&&,
1151 deref_effective_member_type&
1157 member_store_type member;
1159 static constexpr bool has_member =
true;
1161 constexpr wrapped_object_member( object_type& obj )
1162 : member( Access::ugmisc::get(obj) )
1165 wrapped_object_member(
const wrapped_object_member&) =
default;
1166 wrapped_object_member(wrapped_object_member&&) =
default;
1169 constexpr member_return_type get(A&&...args)
const {
return member; }
1172 constexpr member_return_type operator()(A&&...args)
const {
return member; }
1175 static constexpr empty find_ref() {
return {}; }
1177 template<
class T1,
class...T>
1178 static constexpr auto find_ref(T1&& obj, T&&...objs) {
1179 if constexpr ( Access::ugmisc::template has_member<T1> ) {
1180 return wrapped_object_member<T1>{ obj };
1182 return find_ref(std::forward<T>(objs)...);
1196 static constexpr auto with(T&&...objs) {
1197 return find_ref(std::forward<T>(objs)...);
1201 constexpr auto operator() (T&&...objs)
const {
return with<T...>(objs...); }
1247template<
class Access,
class TypeList >
class member_type_access_traits {
1248 using all_types = TypeList;
1249 using normal_types =
1250 filter_type_list<member_::get_is_default_type, all_types, invert_test>;
1251 using default_types =
1252 filter_type_list<member_::get_is_default_type, all_types>;
1254 static_assert( default_types::size <= 1 );
1255 static_assert( default_types::size + normal_types::size == all_types::size );
1257 using access = Access;
1259 template<
bool Found,
class U>
struct result {
1260 static constexpr bool found = Found;
1268 template<
class seq = normal_types >
1269 static constexpr auto find_type_pair() {
1271 if constexpr ( seq::size == 0 ) {
1272 return result<false, void>{};
1274 using first_type = type_list_member<0, seq>;
1275 if constexpr ( access::ugmisc::template has_member_type<first_type> ) {
1278 typename access::ugmisc::template type<first_type>
1281 return find_type_pair< type_list_remove_prefix<1, seq> >();
1286 using result_t =
decltype(find_type_pair());
1292 static constexpr auto find_default_type_pair() {
1293 if constexpr ( default_types::size ) {
1294 return result<true, type_list_member<0, default_types>>{};
1296 return result<false, void>{};
1300 using default_t =
decltype(find_default_type_pair());
1304 static constexpr bool has_member = result_t::found;
1305 static constexpr bool has_default = default_t::found;
1306 static constexpr bool has_type = has_member || has_default;
1307 using type = std::conditional_t<
1309 typename result_t::type,
1310 typename default_t::type
1324 bool HasType = member_type_access_traits<Access, TypeList>::has_type
1326struct member_type_access {
1327 static_assert( ! HasType,
"There is a missing specialisation." );
1328 static constexpr bool has_member =
false;
1329 static constexpr bool has_default =
false;
1330 static constexpr bool has_type =
false;
1332 using safe_type = void;
1336template<
class Access,
class TypeList>
1337struct member_type_access<Access, TypeList, true> {
1338 static constexpr bool has_member
1339 = member_type_access_traits<Access, TypeList>::has_member;
1341 static constexpr bool has_default
1342 = member_type_access_traits<Access, TypeList>::has_default;
1344 static constexpr bool has_type =
true;
1347 =
typename member_type_access_traits<Access, TypeList>::type;
1349 using safe_type = type;
1355template<
class Access,
class...T>
1356class static_member_value_base {
1357 template<
class U>
struct access {
1359 static constexpr bool has_member = Access::ugmisc::template has_static_member<U>;
1360 static constexpr auto& get() {
return Access::ugmisc::template static_get<U>(); }
1363 struct void_wrapper {
1367 template<
bool Found,
class Type=
void_wrapper>
1370 static constexpr bool found = Found;
1375 template<
class accessors = accessor_types>
1376 static constexpr auto find_matching_type() {
1377 if constexpr ( accessors::size == 0 ) {
1378 return result<false>{};
1380 using first_type = type_list_member<0, accessors>;
1381 if constexpr ( first_type::has_member ) {
1382 return result<true, first_type>{};
1384 return find_matching_type<type_list_remove_prefix<1, accessors>>();
1389 using result_type =
decltype(find_matching_type());
1390 using getter_type =
typename result_type::type;
1393 static constexpr bool has_member = result_type::found;
1395 template<
class F,
class...A>
1396 static constexpr decltype(
auto) get(F&& default_get, A&&...args) {
1397 if constexpr ( has_member ) {
1398 return getter_type::get();
1400 return default_get(std::forward<A>(args)...);
1404 static constexpr auto& get() {
return getter_type::get(); }
1406 using safe_matched_type =
typename getter_type::type;
1410template<
bool WithType,
class Access,
class...T>
1411struct static_member_value;
1413template<
class Access,
class...T>
1414struct static_member_value<true, Access, T...>
1415:
public static_member_value_base<Access, T...>
1417 using matched_type =
1418 typename static_member_value_base<Access, T...>::safe_matched_type;
1421template<
class Access,
class...T>
1422struct static_member_value<false, Access, T...>
1423:
public static_member_value_base<Access, T...>
1427template<
class Access,
class...T>
1428using static_member_value_t =
1429 static_member_value<
1430 static_member_value_base<Access, T...>::has_member,
1441template<
class Access,
class...T >
class member_type_access
1442:
public member_::member_type_access<Access, flatten_t<T...>>
1563template<
class Access,
class...T>
1583 template<
class F,
class...A>
1584 static constexpr decltype(
auto)
get(F&& default_get, A&&...args);
1591 static constexpr auto&
get() {
return getter_type::get(); }
@ MEMBER_COPY_NEVER
Always take a reference to the original object.
@ MEMBER_COPY_AUTO
Default. Copy value if safe and trivial to do so.
@ MEMBER_COPY_ALWAYS
Always copy the value.
static constexpr wrapped_objects< void, T... > with(T &&...objs)
static constexpr default_function< F > fallback(F &&f)
static constexpr bool has_member
static constexpr bool has_default
static constexpr bool has_type
static constexpr auto with(T &&...objs)
static constexpr member_value< Access, MEMBER_COPY_AUTO > copy_auto
static constexpr member_value< Access, MEMBER_COPY_ALWAYS > copy_always
static constexpr member_value< Access, MEMBER_COPY_NEVER > copy_never
constexpr decltype(auto) operator()(Args &&...args) const
static constexpr bool is_matched(Args &&...)
static matched_type< Args... > declval_matched(Args &&...) noexcept
static constexpr bool is_matched_v
static constexpr decltype(auto) call(Args &&...args)
typename caller< void, types_list, Args... >::type matched_type
static safe_matched_type< Args... > safe_declval_matched(Args &&...) noexcept
static constexpr member_::fallback_caller< static_member_caller, F > fallback(F &&functor)
static constexpr decltype(auto) get(F &&default_get, A &&...args)
static constexpr auto & get()
static constexpr bool has_member
Encapsulates a list of types.
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.
type_list_apply_each_class< F, flatten_t< T... > > flatten_apply_each_class
typename typelist_::get_type_list_member< I, T >::type type_list_member