Eliminación en tiempo de compilación de la ramificación if / else en C ++

8

En el siguiente ejemplo de código, la ifinstrucción depende del boolparámetro de plantilla, que es una constante en tiempo de compilación. Los compiladores manejan este código de manera diferente:

  • MSVC falla con el error de enlace (que es lo que esperaba), porque la función de plantilla en la elserama carece de especialización para el truevalor del parámetro de plantilla (aunque nunca se llama).

  • GCC y Clang compilan sin problemas y el comportamiento en tiempo de ejecución es correcto. Obviamente, esto se debe a que evalúan la ifdeclaración en tiempo de compilación y eliminan las ramas no utilizadas antes de vincular.

La pregunta es qué comportamiento cumple con los estándares (o es un comportamiento indefinido y ambos son correctos a su manera).

#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
fuente
44
Hola, no es lo que estás buscando, pero puedes mirarif constexpr
Martin Morterol
1
Ambos compiladores tienen razón. Pendientemente, este es un comportamiento no especificado. El estándar C ++ no especifica lo que sucede aquí.
Sam Varshavchik
@SamVarshavchik Aún más pedante, es Comportamiento indefinido (UB). Pero en el mundo real, es un error o funciona. No UB en tiempo de ejecución.
curioso

Respuestas:

11

Todos los compiladores se comportan correctamente.

Su programa es mal formado, no se requiere diagnóstico , porque usted está usando odr a Struct<true>::printIfFalsetravés de la instanciación de Struct<true>::print()requerido desde la llamada withTrue.print();. Una función que se usa fuera de una declaración descartada debe tener una definición en el programa, consulte [basic.def.odr] / 4 ; de lo contrario, el programa está mal formado, no se requiere diagnóstico .

UNA declaración descartada es lo que obtienes si la usas if constexpren una plantilla y la declaración no está en la rama elegida. Entonces, lo que puede hacer para que el programa esté bien formado es usarlo en if constexprlugar de hacerlo if. Esta es una característica de C ++ 17.

nuez
fuente