Eliminação em tempo de compilação da ramificação if / else em C ++

8

No exemplo de código a seguir, a ifinstrução depende do boolparâ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 elseramificação não possui especialização para o truevalor 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 ifinstruçã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;
}
Igor Tolmachov
fonte
4
Oi, não o que você está procurando, mas você pode olharif constexpr
Martin Morterol
1
Ambos os compiladores estão certos. Pedanticamente, esse é um comportamento não especificado. O padrão C ++ não especifica o que acontece aqui.
Sam Varshavchik 27/03
@SamVarshavchik Ainda mais pedanticamente, é o Undefined Behavior (UB). Mas no mundo real, é um erro ou funciona. Nenhum UB em tempo de execução.
curiousguy 29/03

Respostas:

11

Todos os compiladores se comportam corretamente.

Seu programa está incorreto , não é necessário diagnóstico , porque você está usando Struct<true>::printIfFalseo odr através da instanciação do Struct<true>::print()necessário da chamada withTrue.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 constexprem 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 em if constexprvez de if. Este é um recurso do C ++ 17.

noz
fonte