programacion programa lenguaje ejemplos caracteristicas c++ c++11 gcc language-lawyer c++14

c++ - programa - ¿Es una extensión del compilador conforme para tratar las funciones de biblioteca estándar no constexpr como constexpr?



programa c++ (1)

gcc compila el siguiente código sin previo aviso:

#include <cmath> struct foo { static constexpr double a = std::cos(3.); static constexpr double c = std::exp(3.); static constexpr double d = std::log(3.); static constexpr double e1 = std::asin(1.); static constexpr double h = std::sqrt(.1); static constexpr double p = std::pow(1.3,-0.75); }; int main() { }

Ninguna de las funciones de biblioteca estándar utilizadas anteriormente son funciones constexpr , se nos permite usarlas donde se requiere una expresión constante tanto del borrador del estándar C ++ 11 como del borrador del estándar C ++ 14 sección 7.1.5 [dcl.constexpr] :

[...] Si se inicializa mediante una llamada de constructor, esa llamada será una expresión constante (5.19). De lo contrario, o si se utiliza un especificador constexpr en una declaración de referencia, cada expresión completa que aparezca en su inicializador será una expresión constante. [...]

Incluso cuando se usa -std=c++14 -pedantic o -std=c++11 -pedantic no se generan advertencias ( -std=c++11 -pedantic en vivo ). El uso de -fno-builtin produce errores ( -fno-builtin en vivo ), lo que indica que la versión builtin de estas funciones de biblioteca estándar se está tratando como si fueran constexpr

Si bien clang no permite el código con ninguna combinación de banderas que he intentado.

Por lo tanto, esta es una extensión de gcc para tratar al menos algunas funciones integradas como si fueran funciones constexpr , aunque el estándar no las exija explícitamente. Hubiera esperado al menos recibir una advertencia en modo estricto de conformidad, ¿es esta una extensión conforme?


TL; DR

En C ++ 14 esto no está explícitamente permitido, aunque en 2011 parecía que este caso estaría explícitamente permitido. No está claro si para C ++ 11 esto cayó bajo la regla as-if , no creo que lo haga, ya que altera el comportamiento observable, pero ese punto no se aclaró en el tema que menciono a continuación.

Detalles

La respuesta a esta pregunta ha cambiado con el estado en evolución de la edición 2013 de LWG que se abre con:

Suponga que una función en particular no está etiquetada como constexpr en el estándar, pero que, en alguna implementación particular, es posible escribirla dentro de las restricciones constexpr. Si un implementador etiqueta una función como constexpr, ¿es eso una violación del estándar o es una extensión conforme?

En C ++ 11 no estaba claro si la regla as-if lo permitía, pero la propuesta original lo habría permitido explícitamente una vez que fuera aceptado y podemos ver a continuación en el informe de error de gcc que hago referencia, esta fue la suposición hecha por el gcc equipo.

El consenso para permitir esto cambió en 2012 y la propuesta cambió y en C ++ 14 esta es una extensión no conforme. Esto se refleja en el borrador de la sección estándar C ++ 14 17.6.5.6 [constexpr.functions] que dice:

[...] Una implementación no declarará ninguna firma de función de biblioteca estándar como constexpr, excepto aquellas en las que se requiera explícitamente. [..]

y aunque una lectura estricta de esto parece dejar un margen de maniobra para tratar implícitamente a un constructor como si fuera un texto completo, podemos ver en la siguiente cita en el tema que la intención era evitar la divergencia en las implementaciones ya que un código idéntico podría producir un comportamiento diferente cuando se usa SFINAE (el énfasis es mío ):

Cuando se presentó ante el comité completo para votar el estado de WP, se expresó cierta preocupación de que este problema se hubiera resuelto sin pensar lo suficiente en las consecuencias de las implementaciones divergentes de la biblioteca, ya que los usuarios pueden usar SFINAE para observar un comportamiento diferente de un código idéntico .

Podemos ver en el informe de error de gcc [C ++ 0x] sinh vs asinh vs constexpr que el equipo confió en la resolución propuesta anteriormente de LWG 2013 que dice:

[...] Además, una implementación puede declarar que cualquier función sea constexpr si la definición de esa función satisface las restricciones necesarias [...]

al decidir si este cambio para las funciones matemáticas estaba permitido en el modo de conformidad estricta.

Por lo que puedo decir, esto se volvería conforme si -std=c++11 -pedantic una advertencia en modo de conformidad estricta, es decir, usando -std=c++11 -pedantic o si estaba deshabilitado en este modo.

Tenga en cuenta que agregué un comentario al informe de error que explica que la resolución cambió ya que este problema se abordó originalmente.

Jonathan Wakely señaló en otra pregunta una discussion más reciente y parece probable que el informe de error de gcc se vuelva a abrir para abordar este problema de conformidad.

¿Qué pasa con los intrínsecos?

Los intrínsecos del compilador no están cubiertos por el estándar y, por lo que puedo decir, deberían estar exentos de esta regla, por lo que usar:

static constexpr double a = __builtin_cos(3.);

Debería ser permitido. Esta pregunta surgió en el informe de error y la opinión de Daniel Krügler fue:

[...] Las funciones de la biblioteca y otros elementos intrínsecos probablemente se pueden considerar como excepciones, porque no se requiere que sean "explicables" por las reglas normales del lenguaje.