c++ c++11 constexpr

c++ - ¿Puede agregar ''constexpr'' cambiar el comportamiento?



c++11 (2)

Dados dos programas donde la única diferencia en el código fuente es la presencia o ausencia de un constexpr, ¿es posible que el significado del programa cambie?

Sí, esto es al menos cierto para las funciones constexpr. Es la razón por la que no se permite a las implementaciones elegir qué funciones estándar están marcadas como constexpr, el problema principal es que los usuarios pueden observar diferentes comportamientos a través de SFINAE. Esto se documenta en la edición 2013 de LWG: ¿Los implementadores de bibliotecas tienen la libertad de agregar constexpr? que dice ( énfasis mío ):

Se expresó cierta preocupación cuando se presentó ante el comité completo para votar sobre el estado WP que este problema se había resuelto sin pensar lo suficiente en las consecuencias de las implementaciones de bibliotecas divergentes, ya que los usuarios pueden usar SFINAE para observar un comportamiento diferente del código idéntico . El problema regresó al estado de Revisión y se discutirá nuevamente en Portland con un grupo más grande. Nota para Portland: John Spicer ha aceptado representar las preocupaciones de Core durante cualquier discusión de este tipo dentro de LWG.

Dados dos programas donde la única diferencia en el código fuente es la presencia o ausencia de un constexpr , ¿es posible que el significado del programa cambie?

En otras palabras, si hubiera una opción de compilación para pedirle al compilador que trate realmente de inferir constexpr cuando sea posible, ¿rompería el código estándar existente y / o cambiaría su significado de manera incorrecta?

Imagine tratar con una base de código donde el desarrollador original olvidó incluir constexpr en lugares donde era posible, tal vez un código escrito antes de C ++ 11. Sería fantástico si el compilador constexpr para ayudarlo a continuar con su trabajo. Por supuesto, tal vez debería advertirle cada vez que haga esta inferencia, alentándolo a agregar explícitamente el constexpr más tarde. Pero aún sería útil. ¿Mi preocupación es que pueda romper cosas?

Hasta ahora, lo único que puedo pensar es que constexpr funciones constexpr están implícitamente en inline y puede haber situaciones en las que agregar en inline puede cambiar las cosas de manera incorrecta; por ejemplo si rompes la regla de una definición.


Hay un truco fácil:

template<int n>struct i{}; int foo(int){return 0;} constexpr int foo(char){return ''a'';} template<class T=int, T x=1,i<foo(x)>* =nullptr> bool bar(){return true;} template<class T=int, T x=1,class...Ts> bool bar(Ts...){return false;}

si int foo(int) es constexpr, se elige una sobrecarga diferente de bar por defecto.

Con un código diferente en ejecución, cualquier cambio de comportamiento puede ocurrir.

Ejemplo en vivo (simplemente cambie lo que #define X está comentado).

Diseño del ejemplo:

La sobrecarga de caracteres evita que el código anterior no se forme correctamente, no se requiere diagnóstico, ya que todas las plantillas deben tener una especialización válida. foo<char> suministra eso. En la práctica, no se requiere su existencia: ADL podría encontrar un foo desde muy lejos, sobrecargado en un some_type* , luego pasar some_type* como T Lo que significa que ninguna unidad de compilación podría probar que el código estaba mal formado.

La Ts... hace que la sobrecarga de bar menos preferida. Así que si el primero coincide, no hay ambigüedad. Solo si la primera no coincide (debido a un SFINAE causado por foo(x) no es constexpr ) se constexpr la segunda sobrecarga (o si, por ejemplo, alguien le pasa los argumentos).