Reputation: 4840
Consider this code:
template < size_t... Indices >
void something(std::index_sequence<Indices...>)
{
// how to obtain the following call where N is sizeof...(Indices)?
// foo(f(0),g(0),f(1),g(1),...,f(N-1),g(N-1));
}
Upvotes: 4
Views: 422
Reputation: 303337
The key to answering a question like:
// how to obtain the following call where N is sizeof...(Indices)?
// foo(f(0),g(0),f(1),g(1),...,f(N-1),g(N-1));
is to formulate how to actually generate such a pack expansion. We have 2N
arguments, which would like:
+=====+======+
| idx | expr |
+-----+------+
| 0 | f(0) |
| 1 | g(0) |
| 2 | f(1) |
| 3 | g(1) |
| ....
+=====+======+
In C++17, we can write such an expression with if constexpr
:
template <size_t I>
auto expr() {
if constexpr (I % 2 == 0) {
// even indices are fs
return f(I / 2);
} else {
// odds are gs
return g(I / 2);
}
}
Which can even be a lambda that takes an integral_constant
as an argument. So we really just need to turn our N
arguments into 2N
arguments, which is just a matter of adding more indices:
template <auto V>
using constant = std::integral_constant<decltype(V), V>;
template < size_t... Indices >
void something(std::index_sequence<Indices...>) {
auto expr = [](auto I) {
if constexpr (I % 2 == 0) {
return f(I / 2);
} else {
return g(I / 2);
}
}
return foo(
expr(constant<Indices>{})..., // 0, ..., N-1
expr(constant<Indices + sizeof...(Indices)>{})... // N, ..., 2N-1
);
}
Upvotes: 3
Reputation: 66230
The best I can imagine is the use of std::tuple_cat
and std::make_pair
to make a std::tuple
of arguments of foo()
.
Unfortunately I know how to do it only with an helper function to call foo()
template <typename T, std::size_t... I>
void somethingH (T const & t, std::index_sequence<I...> const &)
{ foo(std::get<I>(t)...); }
template <std::size_t... I>
void something (std::index_sequence<I...> const &)
{
somethingH(std::tuple_cat(std::make_pair(f(I), g(I))...),
std::make_index_sequence<(sizeof...(I) << 1)>{});
}
Using std::apply
, available only starting from C++17, you can use a lambda function to select the correct foo
(as SirGuy suggested; thanks!) and avoid the helper function
template <std::size_t... I>
void something (std::index_sequence<I...> const &)
{
std::apply([](auto && ... as)
{ return foo(std::forward<decltype(as)>(as)...); },
std::tuple_cat(std::make_pair(f(I), g(I))...));
}
The following is a full C++17 working example
#include <iostream>
#include <utility>
#include <tuple>
int f (std::size_t n)
{ return n; }
int g (std::size_t n)
{ return -n; }
template <typename ... Args>
void foo (Args ... as)
{ (std::cout << ... << as) << std::endl; }
template <std::size_t... I>
void something (std::index_sequence<I...> const &)
{
std::apply([](auto && ... as)
{ return foo(std::forward<decltype(as)>(as)...); },
std::tuple_cat(std::make_pair(f(I), g(I))...));
}
int main()
{
something(std::make_index_sequence<7U>{});
}
Upvotes: 2