Considere el siguiente ejemplo ( fragmento (0) ):
struct X
{
constexpr int get() const { return 0; }
};
void foo(const X& x)
{
constexpr int i = x.get();
}
int main()
{
foo(X{});
}
El ejemplo anterior se compila con todas las versiones g++
anteriores g++ 10.x
y nunca compiladas bajo clang++
. El mensaje de error es:
error: 'x' is not a constant expression 8 | constexpr int i = x.get(); |
ejemplo en vivo en godbolt.org
Sin embargo, el tipo de error tiene sentido, ya x
que nunca es una expresión constante en el cuerpo de foo
:
X::get()
está marcadoconstexpr
y no depende del estado dex
;Cambiar
const X&
aconst X
hace que el código se compile con cada fragmento del compilador (en godbolt.org) (1) .
Se vuelve aún más interesante cuando marco X::get()
como static
( (en godbolt.org) fragmento (2) ). Con ese cambio, todas las versiones probadas de g++
compilación (incluida la troncal), aunque clang++
siempre fallan al compilar.
Entonces, mis preguntas:
¿Es
g++ 9.x
correcto aceptar el fragmento (0) ?¿Todos los compiladores son correctos al aceptar el fragmento (1) ? Si es así, ¿por qué es importante la referencia?
Son
g++ 9.x
yg++ trunk
correcta al aceptar fragmento (2) ?
x
en foo
no es una expresión constante. Incluso hay un informe de error antiguo (rechazado informalmente) en el sonido metálico por su comportamiento correcto (mientras que GCC tenía un error real).