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...>{});
  }
};
Compiler Explorer example
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_constants). Arguably, the result looks better too - it's less busy. I prefer this in C++20 anyway.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With