1+ #ifndef HELPER_H
2+ #define HELPER_H
3+
4+ namespace helper {
5+
6+ using size_t = decltype (sizeof 0 );
7+
8+ namespace detail {
9+
10+ struct UniversalType {
11+ template <class T >
12+ operator T () const ;
13+ };
14+
15+ template <typename T, typename Is, typename =void >
16+ struct is_aggregate_constructible_from_n_impl : std::false_type {};
17+
18+ template <typename T, size_t ...Is>
19+ struct is_aggregate_constructible_from_n_impl <T, std::index_sequence<Is...>, std::void_t <decltype (T{(void (Is), UniversalType{})...})>> : std::true_type {};
20+
21+ template <typename T, size_t N>
22+ using is_aggregate_constructible_from_n_helper = is_aggregate_constructible_from_n_impl<T, std::make_index_sequence<N>>;
23+
24+ template <typename T, size_t N>
25+ struct is_aggregate_constructible_from_n {
26+ constexpr static bool value = is_aggregate_constructible_from_n_helper<T, N>::value && !is_aggregate_constructible_from_n_helper<T, N+1 >::value;
27+ };
28+
29+ template <typename T>
30+ constexpr bool false_type = false ;
31+
32+ } // namespace detail
33+
34+ template <class Argument >
35+ constexpr size_t CountMembers () {
36+ if constexpr (detail::is_aggregate_constructible_from_n<Argument, 0 >::value) return 0 ;
37+ else if constexpr (detail::is_aggregate_constructible_from_n<Argument, 1 >::value) return 1 ;
38+ else if constexpr (detail::is_aggregate_constructible_from_n<Argument, 2 >::value) return 2 ;
39+ else if constexpr (detail::is_aggregate_constructible_from_n<Argument, 3 >::value) return 3 ;
40+ else if constexpr (detail::is_aggregate_constructible_from_n<Argument, 4 >::value) return 4 ;
41+ else if constexpr (detail::is_aggregate_constructible_from_n<Argument, 5 >::value) return 5 ;
42+ else if constexpr (detail::is_aggregate_constructible_from_n<Argument, 6 >::value) return 6 ;
43+ else if constexpr (detail::is_aggregate_constructible_from_n<Argument, 7 >::value) return 7 ;
44+ else if constexpr (detail::is_aggregate_constructible_from_n<Argument, 8 >::value) return 8 ;
45+ else if constexpr (detail::is_aggregate_constructible_from_n<Argument, 9 >::value) return 9 ;
46+ else if constexpr (detail::is_aggregate_constructible_from_n<Argument, 10 >::value) return 10 ;
47+ else {
48+ static_assert (detail::false_type<Argument>, " Unsupported number of members." );
49+ return 100 ; // Silence warnings about missing return value
50+ }
51+ }
52+
53+ template <
54+ class Argument ,
55+ class FunctionObject
56+ >
57+ constexpr auto invoke (Argument & arg, FunctionObject&& f) {
58+ constexpr size_t M = helper::CountMembers<Argument>();
59+ if constexpr (M == 0 ) {
60+ return f ();
61+ } else if constexpr (M == 1 ) {
62+ auto & [m00] = arg;
63+ return f (m00);
64+ } else if constexpr (M == 2 ) {
65+ auto & [m00, m01] = arg;
66+ return f (m00, m01);
67+ } else if constexpr (M == 3 ) {
68+ auto & [m00, m01, m02] = arg;
69+ return f (m00, m01, m02);
70+ } else if constexpr (M == 4 ) {
71+ auto & [m00, m01, m02, m03] = arg;
72+ return f (m00, m01, m02, m03);
73+ } else if constexpr (M == 5 ) {
74+ auto & [m00, m01, m02, m03, m04] = arg;
75+ return f (m00, m01, m02, m03, m04);
76+ } else if constexpr (M == 6 ) {
77+ auto & [m00, m01, m02, m03, m04, m05] = arg;
78+ return f (m00, m01, m02, m03, m04, m05);
79+ } else if constexpr (M == 7 ) {
80+ auto & [m00, m01, m02, m03, m04, m05, m06] = arg;
81+ return f (m00, m01, m02, m03, m04, m05, m06);
82+ } else if constexpr (M == 8 ) {
83+ auto & [m00, m01, m02, m03, m04, m05, m06, m07] = arg;
84+ return f (m00, m01, m02, m03, m04, m05, m06, m07);
85+ } else if constexpr (M == 9 ) {
86+ auto & [m00, m01, m02, m03, m04, m05, m06, m07, m08] = arg;
87+ return f (m00, m01, m02, m03, m04, m05, m06, m07, m08);
88+ } else if constexpr (M == 10 ) {
89+ auto & [m00, m01, m02, m03, m04, m05, m06, m07, m08, m09] = arg;
90+ return f (m00, m01, m02, m03, m04, m05, m06, m07, m08, m09);
91+ } else {
92+ static_assert (detail::false_type<Argument>, " Unsupported number of members." );
93+ return void (); // Silence warnings about missing return value
94+ }
95+ }
96+
97+ template <
98+ template <class > class F_out ,
99+ template <class > class F_in ,
100+ template <template <class > class > class S ,
101+ class FunctionObject
102+ >
103+ struct memberwise {
104+ FunctionObject f;
105+
106+ template <class ... Args> // HACK: NVCC cannot deduce template parameters of f.operator() like so: { f(args)... }
107+ constexpr S<F_out> operator ()(Args&... args) const { return {f.template operator ()<F_in>(args)...}; }
108+ };
109+
110+ template <
111+ template <class > class F_out ,
112+ template <class > class F_in ,
113+ template <template <class > class > class S ,
114+ class FunctionObject
115+ >
116+ constexpr S<F_out> invoke_on_members (S<F_in> & s, FunctionObject&& f) {
117+ return invoke (s, memberwise<F_out, F_in, S, FunctionObject>{f});
118+ }
119+
120+ template <
121+ template <class > class F_out ,
122+ template <class > class F_in ,
123+ template <template <class > class > class S ,
124+ class FunctionObject
125+ >
126+ constexpr S<F_out> invoke_on_members (const S<F_in> & s, FunctionObject&& f) {
127+ return invoke (s, memberwise<F_out, F_in, S, FunctionObject>{f});
128+ }
129+
130+ } // namespace helper
131+
132+ #endif // HELPER_H
0 commit comments