No exemplo de código a seguir, a if
instrução depende do bool
parâmetro do modelo, que é uma constante em tempo de compilação. Os compiladores manipulam esse código de maneira diferente:
MSVC falha com erro de link (o que eu esperava), porque a função de modelo na
else
ramificação não possui especialização para otrue
valor do parâmetro de modelo (mesmo que nunca seja chamado).O GCC e o Clang são compilados sem problemas e o comportamento em tempo de execução está correto. Obviamente, isso ocorre porque eles avaliam a
if
instrução no tempo de compilação e removem ramificações não utilizadas antes da vinculação.
A questão é qual comportamento é compatível com o padrão (ou é um comportamento indefinido e ambos estão corretos à sua maneira)?
#include <iostream>
template<const bool condition>
struct Struct
{
void print()
{
if (condition)
{
std::cout << "True\n";
}
else
{
printIfFalse();
}
}
private:
void printIfFalse();
};
template <>
void Struct<false>::printIfFalse()
{
std::cout << "False\n";
}
int main()
{
Struct<true> withTrue{};
withTrue.print();
Struct<false> withFalse{};
withFalse.print();
return 0;
}
c++
templates
language-lawyer
compiler-optimization
template-specialization
Igor Tolmachov
fonte
fonte
if constexpr
Respostas:
Todos os compiladores se comportam corretamente.
Seu programa está incorreto , não é necessário diagnóstico , porque você está usando
Struct<true>::printIfFalse
o odr através da instanciação doStruct<true>::print()
necessário da chamadawithTrue.print();
. Uma função que é usada por odr fora de uma instrução descartada deve ter uma definição no programa, consulte [basic.def.odr] / 4 ; caso contrário, o programa está mal formado, não é necessário diagnóstico .Uma declaração descartada é o que você obtém se usar
if constexpr
em um modelo e a declaração não estiver no ramo escolhido. Portanto, o que você pode fazer para tornar o programa bem formado é usar emif constexpr
vez deif
. Este é um recurso do C ++ 17.fonte