@@ -70,54 +70,44 @@ constexpr auto is_cartesian_product_callable<Function, types<Args...>, types<Typ
70
70
is_cartesian_product_callable<Function, types<Args..., Types>, Rest...>
71
71
);
72
72
73
- // The primary template just rotates the parameters
74
- template <std::size_t index, template <typename > typename GetTypes, typename Arg, typename ... Args>
75
- constexpr auto is_variants_then_visit_function = is_variants_then_visit_function<
76
- index - 1U ,
77
- GetTypes,
78
- Args...,
79
- Arg
80
- >;
81
- // The specialization forwards to the implementation that does the real work
82
- template <template <typename > typename GetTypes, typename Function, typename ... Variants>
83
- constexpr auto is_variants_then_visit_function<
84
- 0U ,
85
- GetTypes,
86
- Function,
87
- Variants...
88
- > = is_cartesian_product_callable<
89
- Function,
90
- types<>,
91
- GetTypes<Variants>...
92
- >;
93
-
94
-
95
- template <std::size_t ... indexes>
96
- constexpr decltype (auto ) visit_implementation(
73
+ template <template <typename > typename GetTypes, typename Function, typename ... Variants, std::size_t ... indexes>
74
+ consteval auto is_variants_then_visit_function (std::index_sequence<indexes...>) -> bool {
75
+ return is_cartesian_product_callable<
76
+ Function,
77
+ types<>,
78
+ GetTypes<Variants...[indexes]>...
79
+ >;
80
+ }
81
+
82
+ template <bool use_index, std::size_t , std::size_t ... indexes>
83
+ constexpr auto visit_implementation (
97
84
auto && function,
98
85
std::index_sequence<indexes...>,
99
86
bounded::constant_t <0 >,
100
87
auto && ... variants
101
- ) requires(sizeof ...(indexes) == sizeof...(variants)) {
102
- return OPERATORS_FORWARD (function)(
103
- indexed_value<
104
- decltype (OPERATORS_FORWARD (variants)[bounded::constant<indexes>]),
105
- indexes
106
- >(OPERATORS_FORWARD (variants)[bounded::constant<indexes>])...
107
- );
88
+ ) -> decltype(auto ) requires(sizeof ...(indexes) == sizeof...(variants)) {
89
+ if constexpr (use_index) {
90
+ return OPERATORS_FORWARD (function)(
91
+ indexed_value<
92
+ decltype (OPERATORS_FORWARD (variants)[bounded::constant<indexes>]),
93
+ indexes
94
+ >(OPERATORS_FORWARD (variants)[bounded::constant<indexes>])...
95
+ );
96
+ } else {
97
+ return OPERATORS_FORWARD (function)(
98
+ OPERATORS_FORWARD (variants)[bounded::constant<indexes>]...
99
+ );
100
+ }
108
101
}
109
102
110
- // This function accepts the pack of all variants twice. It passes over them
111
- // once to get all the indexes, then again to pull out the values.
112
- template <std::size_t ... indexes>
113
- constexpr decltype (auto ) visit_implementation(
103
+ template <bool use_index, std::size_t variant_index, std::size_t ... indexes>
104
+ constexpr auto visit_implementation (
114
105
auto && function,
115
106
std::index_sequence<indexes...> initial_indexes,
116
107
auto offset,
117
- auto const & variant,
118
108
auto && ... variants
119
- ) requires(sizeof ...(indexes) < sizeof...(variants)) {
120
- auto const search_index = variant .index ().integer ();
109
+ ) -> decltype( auto ) requires(sizeof ...(indexes) < sizeof...(variants)) {
110
+ auto const search_index = variants...[variant_index] .index ().integer ();
121
111
auto const this_search = search_index - offset;
122
112
123
113
// Cannot use a lambda because there is no return type that would be valid
@@ -127,7 +117,7 @@ constexpr decltype(auto) visit_implementation(
127
117
if constexpr (numeric_traits::max_value<decltype (this_search)> < (index)) { \
128
118
std::unreachable (); \
129
119
} else { \
130
- return ::tv::visit_implementation ( \
120
+ return ::tv::visit_implementation<use_index, variant_index + 1 > ( \
131
121
OPERATORS_FORWARD (function), \
132
122
std::index_sequence<indexes..., static_cast <std::size_t >(offset + (index))>{}, \
133
123
0_bi, \
@@ -159,11 +149,10 @@ constexpr decltype(auto) visit_implementation(
159
149
if constexpr (numeric_traits::max_value<decltype (this_search)> < max_index) {
160
150
std::unreachable ();
161
151
} else {
162
- return ::tv::visit_implementation (
152
+ return ::tv::visit_implementation<use_index, variant_index> (
163
153
OPERATORS_FORWARD (function),
164
154
initial_indexes,
165
155
offset + max_index,
166
- variant,
167
156
OPERATORS_FORWARD (variants)...
168
157
);
169
158
}
@@ -172,65 +161,44 @@ constexpr decltype(auto) visit_implementation(
172
161
#undef VISIT_IMPL
173
162
}
174
163
175
- template <typename , auto >
176
- concept any_with_value = true ;
177
-
178
164
// Often, we want to write a function that accepts a variadic number of
179
165
// arguments and a function. We would like to accept the function parameter
180
166
// last, since that gives the best syntax when passing a lambda. However, you
181
167
// cannot put something after a variadic pack, therefore the function is part of
182
168
// the pack. rotate_transform allows us to write an interface that accepts stuff
183
169
// and a function to operate on the stuff, but allows us to decide whether to
184
170
// pass values or indexed values to the user's function.
185
- template <std::size_t ... indexes>
186
- constexpr auto rotate_transform_impl (std::index_sequence<indexes...>) {
187
- return [](
188
- auto const transform,
189
- any_with_value<indexes> auto && ... variants,
190
- auto && function
191
- ) -> decltype (auto ) {
192
- return ::tv::visit_implementation (
193
- transform (OPERATORS_FORWARD (function)),
194
- std::index_sequence<>{},
195
- 0_bi,
196
- variants...,
197
- OPERATORS_FORWARD (variants)...
198
- );
199
- };
200
- }
201
-
202
- constexpr auto rotate_transform (auto const transform, auto && ... args) -> decltype(auto ) {
203
- auto impl = ::tv::rotate_transform_impl (std::make_index_sequence<sizeof ...(args) - 1 >());
204
- return impl (transform, OPERATORS_FORWARD (args)...);
171
+ template <bool use_index, std::size_t ... indexes>
172
+ constexpr auto rotate_transform (auto && function, std::index_sequence<indexes...>, auto && ... args) -> decltype(auto ) {
173
+ return ::tv::visit_implementation<use_index, 0 >(
174
+ OPERATORS_FORWARD (function),
175
+ std::index_sequence<>(),
176
+ 0_bi,
177
+ OPERATORS_FORWARD (args...[indexes])...
178
+ );
205
179
}
206
180
207
- struct identity {
208
- static constexpr auto operator ()(auto && function) -> auto && {
209
- return function;
210
- }
211
- };
212
-
213
181
// Accepts any number of variants (including 0) followed by one function
214
182
export constexpr auto visit_with_index = []<typename ... Args>(Args && ... args) static -> decltype (auto )
215
- requires is_variants_then_visit_function<sizeof...(Args ) - 1U, indexed_variant_types, Args...>
183
+ requires( is_variants_then_visit_function<indexed_variant_types, Args...[ sizeof ...(args ) - 1], Args...>(std::make_index_sequence< sizeof ...(Args) - 1>()))
216
184
{
217
- return ::tv::rotate_transform (identity (), OPERATORS_FORWARD (args)...);
218
- };
219
-
220
- struct remove_index {
221
- static constexpr auto operator ()(auto && function) {
222
- return [&](auto && ... args) -> decltype (auto ) {
223
- return OPERATORS_FORWARD (function)(OPERATORS_FORWARD (args).value ()...);
224
- };
225
- }
185
+ return ::tv::rotate_transform<true >(
186
+ OPERATORS_FORWARD (args...[sizeof ...(args) - 1 ]),
187
+ std::make_index_sequence<sizeof ...(args) - 1 >(),
188
+ OPERATORS_FORWARD (args)...
189
+ );
226
190
};
227
191
228
192
// Accepts any number of variants (including 0) followed by one function with
229
193
// arity equal to the number of variants
230
194
export constexpr auto visit = []<typename ... Args>(Args && ... args) static -> decltype (auto )
231
- requires is_variants_then_visit_function<sizeof...(Args ) - 1U, variant_types, Args...>
195
+ requires( is_variants_then_visit_function<variant_types, Args...[ sizeof ...(args ) - 1], Args...>(std::make_index_sequence< sizeof ...(Args) - 1>()))
232
196
{
233
- return ::tv::rotate_transform (remove_index (), OPERATORS_FORWARD (args)...);
197
+ return ::tv::rotate_transform<false >(
198
+ OPERATORS_FORWARD (args...[sizeof ...(args) - 1 ]),
199
+ std::make_index_sequence<sizeof ...(args) - 1 >(),
200
+ OPERATORS_FORWARD (args)...
201
+ );
234
202
};
235
203
236
204
} // namespace tv
0 commit comments