¿Por qué esta "variable externa indefinida" no da como resultado un error de enlazador en C++ 17?
linker-errors c++17 (4)
Debido a que el compilador produce errores de compilación, el enlazador produciría errores de enlazador ...
No en serio:
if constexpr (true)
siempre es cierto, por lo que el compilador ignora el resto de la cláusula if porque nunca se alcanza. Entonces nunca se usa en realidad.
He compilado y ejecuté el siguiente programa en un compilador C ++ 17 (Coliru). En el programa, declare una variable extern
, pero no la definí . Sin embargo, el compilador no da un error de enlazador .
#include <iostream>
extern int i; // Only declaration
int func()
{
if constexpr (true)
return 0;
else if (i)
return i;
else
return -1;
}
int main()
{
int ret = func();
std::cout<<"Ret : "<<ret<<std::endl;
}
¿Por qué el compilador no da un error de enlazador?
En su caso, la variable se utiliza solo en declaraciones descartadas. Sin embargo, incluso si ignoramos ese hecho, la especificación del lenguaje C ++ aún establece explícitamente que no se requiere diagnóstico para las definiciones faltantes.
3.2 Regla de una sola definición
4 Cada programa debe contener exactamente una definición de cada función o variable no en línea que se usa en ese programa fuera de una declaración descartada (6.4.1); no se requiere diagnóstico .
La especificación del lenguaje comprende que un compilador de optimización puede ser lo suficientemente inteligente como para eliminar todos los usos odr de una variable. En ese caso, sería excesivo e innecesario requerir que la implementación detecte e informe las potenciales violaciones a la ODR.
Por lo general, esto se ha respondido, pero si está interesado, cppreference.com tiene exactamente este ejemplo para constexpr si :
Constexpr If
La declaración que comienza con
if constexpr
se conoce como constexpr if statement .En una declaración constexpr if, el valor de la condición debe ser una expresión constante convertida contextualmente de tipo bool. Si el valor es verdadero, entonces statement-false se descarta (si está presente), de lo contrario, statement-true se descarta.
[...]
La declaración descartada puede odr-use una variable que no está definida:
extern int x; // no definition of x required
int f() {
if constexpr (true)
return 0;
else if (x)
return x;
else
return -x;
}
Porque la variable no se usa odr. Tienes un constexpr if
allí eso siempre descarta la rama que podría usarlo.
Uno de los puntos de constexpr if
es que la rama descartada no necesita compilarse, solo estar bien formada. Así es como podemos realizar llamadas a funciones miembro no existentes en una rama descartada.