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.xy 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 xque nunca es una expresión constante en el cuerpo de foo:
X::get()está marcadoconstexpry no depende del estado dex;Cambiar
const X&aconst Xhace 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.xcorrecto 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.xyg++ trunkcorrecta al aceptar fragmento (2) ?

xenfoono 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).Respuestas:
No.
Sí lo son.
Una expresión constante no puede usar una expresión id nombrando una referencia que no tenga una inicialización de expresión constante previa o que comience su vida útil durante la evaluación de la expresión constante. [expr.const] /2.11 ( igual en C ++ 20 )
Lo mismo no es cierto si está nombrando una variable sin referencia sin involucrar ninguna conversión de valor a valor.
x.get()solo se refiere axlvalue y solo llama a unaconstexprfunción que en realidad no accede a ningún miembrox, por lo que no hay problema.No, porque la expresión todavía contiene la subexpresión
xque viola la regla mencionada anteriormente.fuente