Tenho uma operação cara que quero chamar condicionalmente dependendo do tipo de template. A função ingênua se parece basicamente com isso.
template <typename T>
void FooNaive( const std::vector<ExpensiveStruct<T>>& vec )
{
std::vector<ExpensiveStruct<float>> vecAsFloat;
if constexpr ( std::is_same_v<T, float> )
vecAsFloat = vec; // expensive copy I want to avoid
else
{
vecAsFloat.reserve( vec.size() );
for ( const auto& s : vec )
vecAsFloat.push_back( ConvertExpensiveStruct( s ) ); // <-- does not compile for floats
}
// ...use vecAsFloat...
}
Para evitar a cópia cara do primeiro branch, tentei fazer vecAsFloat
uma referência const. No entanto, devido a ConvertExpensiveStruct
não compilar para float
tipos (segundo branch), ainda preciso de um if constexpr
in ali.
Esta é minha tentativa atual:
template <typename T>
void FooAttempt( const std::vector<ExpensiveStruct<T>>& vec )
{
std::vector<ExpensiveStruct<float>> dummyVecAsFloat;
if constexpr ( !std::is_same_v<T, float> )
{
dummyVecAsFloat.reserve( vec.size() );
for ( const auto& s : vec )
dummyVecAsFloat.push_back( ConvertExpensiveStruct( s ) );
}
const std::vector<ExpensiveStruct<float>>& vecAsFloat = std::is_same_v<T, float> ? vec : dummyVecAsFloat;
// use vecAsFloat...
}
Também pensei em colocar o loop de conversão em um lambda para ser chamado no local dentro do operador ternário, mas isso significaria que ele teria que retornar uma referência const para sua variável local (estende o tempo de vida, mas ainda é feio) ou, na pior das hipóteses, retornar uma cópia por valor (lambdas têm NRVO?).
Mas parece muito complicado. Existe uma maneira de escrever isso de forma mais simples, ou pelo menos com intenção mais clara?