Comecei a usar esse tipo de construção, que depende dos parâmetros de modelo explícitos do C++20 para 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...>{});
}
};
Existe uma maneira relativamente elegante de fazer isso em C++17 ou C++14? Ou devo apenas tornar C++20 um requisito agora?
Então é importante reconhecer qual parte você realmente precisa. Quando você escreve isto:
O que você realmente precisa é
Is...
. Ou, mais genericamente, o que você realmente precisa é de um pacote de valores constantes. No exemplo acima, você está aceitando um parâmetro deindex_sequence<Is...>
- que é um parâmetro, cujo tipo tem o pacote de valores constantes nele.Mas uma maneira diferente de fazer isso seria aceitar
N
parâmetros diferentes, onde o primeiro parâmetro é do tipointegral_constant<size_t, 0>
e o segundo parâmetro é do tipointegral_constant<size_t, 1>
, e assim por diante. Se você pudesse produzir esses argumentos, então a parte lambda se tornariaNote que o corpo é idêntico, eu apenas alterei a aparência do(s) parâmetro(s). E agora este é um lambda C++14 válido.
Então o resto do problema é produzir o modelo de função
with<N>(f)
, que chamaf(integral_constant<size_t, 0>{}, integral_constant<size_t, 1>{},..., integral_constant<size_t, N-1>{})
o que permite que você chame:E escrever
with
em C++14 é direto. É realmente o mesmoindex_sequence
truque, com uma indireção extra (porque você precisa então mudar o umindex_sequence
para oN
integral_constant
s). Indiscutivelmente, o resultado parece melhor também - é menos movimentado. Eu prefiro isso em C++20 de qualquer maneira.Uma maneira possível é "colocar" a sequência diretamente no modelo de classe:
Uma abordagem direta é tornar o lambda uma função membro:
Mas não tenho certeza se ele se qualifica como relativamente elegante.
Uma maneira de ignorar a falta de lambda de modelo é ter um método de modelo que retorna o lambda:
Demonstração
Isso deve funcionar a partir do c++14.
Nota: isso é de alguma forma similar à resposta anterior que eu não tinha visto antes de postar. Talvez ela sublinhe um pouco mais a intenção subjacente, ou seja, fazer um modelo lambda, mas é ainda menos amigável.
Então, c++20 é uma boa ideia se você puder usá-lo em seu contexto.