I have started using this type of construction, which depends on C++20's explicit template parameters for lambdas:
template<typename... Ts>
struct Foo
{
std::tuple<Ts...> bars;
auto get_labels(const std::array<std::size_t,sizeof...(Ts)>& indices) const
{
// construct tuple from bar labels
return [&]<std::size_t... Is>(std::index_sequence<Is...>) {
return std::make_tuple(std::get<Is>(bars).get_label(indices[Is])...);
}(std::index_sequence_for<Ts...>{});
}
};
How can I do this in C++17 or C++14 (without explicit template parameters for lambdas)?
So it's important to recognize what part you actually need. When you write this:
// construct tuple from bar labels
return [&]<std::size_t... Is>(std::index_sequence<Is...>) {
return std::make_tuple(std::get<Is>(bars).get_label(indices[Is])...);
}(std::index_sequence_for<Ts...>{});
What you actually need is Is...
. Or, more generally, what you actually need is a pack of constant values. In the above example, you are accepting a parameter of index_sequence<Is...>
- that's one parameter, whose type has the pack of constant values in it.
But a different way to do it would be to accept N
different parameters, where the first parameter is of type integral_constant<size_t, 0>
and the second parameter is of type integral_constant<size_t, 1>
, and so forth. If you could produce those arguments, then the lambda part becomes
[&](auto... Is){
return std::make_tuple(std::get<Is>(bars).get_label(indices[Is])...);
}
Note that the body is identical, I just changed what the parameter(s) looks like. And this is now a valid C++14 lambda.
So the rest of the problem is producing the function template with<N>(f)
, which calls f(integral_constant<size_t, 0>{}, integral_constant<size_t, 1>{},..., integral_constant<size_t, N-1>{})
which allows you to call:
return with<sizeof...(Ts)>([&](auto... Is){
return std::make_tuple(std::get<Is>(bars).get_label(indices[Is])...);
})
And writing with
in C++14 is straightforward. It's really just the same index_sequence
trick, with an extra indirection (cause you need to then change the one index_sequence
into the N
integral_constant
s). Arguably, the result looks better too - it's less busy. I prefer this in C++20 anyway.