Preciso acessar um valor std::tuple
por índice em tempo de execução. Para isso escrevi uma função que retorna a std::variant
com os mesmos tipos inicializados para o índice especificado. A implementação envolve instanciações de modelos recursivos:
template<std::size_t N>
constexpr auto get_n = [](/*tuple-like*/auto&& t, std::size_t index)
{
using variant_type = decltype(std::apply([](auto&&... v){
return std::variant<std::monostate, std::remove_cvref_t<decltype(v)>...>{};
}, t));
constexpr auto size = std::tuple_size_v<std::remove_cvref_t<decltype(t)>>;
if constexpr(N > size)
return variant_type{};
else
{
if(N == index + 1)
return variant_type(std::in_place_index<N>, std::get<N - 1>(t));
else
return get_n<N + 1>(t, index);
}
};
constexpr auto tuple_to_variant(/*tuple-like*/auto&& t, std::size_t index)
{
return get_n<1>(std::forward<decltype(t)>(t), index);
}
Estou usando compiladores c++23. O problema é que apenas o gcc compila sem erros. Os compiladores clang e MSVC entram em loop infinito de instanciação. Isso é um bug nos compiladores? Como posso corrigir esse código que ele compila nos três compiladores?
Aqui está a demonstração do Compiler Explorer
Como você está chamando o lambda recursivamente, isso só é possível com um parâmetro de objeto explícito do C++ 23. Isso deve funcionar:
Demonstração
Funciona se você usar
em vez de. Não há razão para
get_n
ser um lambda.E esta é outra solução possível aceita por todo compilador. A vantagem é que a função lambda é local
tuple_to_variant
, portanto não cria nenhum nome no escopo externo.Demonstração do Explorador de Código
Uma implementação não recursiva com tipos detalhados seria:
Eu gosto de colocar o argumento ativo/operacional/de seleção (
i
) primeiro e o argumento passivo (t
) por último.