c++ c++11 constexpr

¿En qué parte del estándar C++ 11 especifica cuándo se puede evaluar una función constexpr durante la traducción?



c++11 (4)

Al combinar el FDIS, he encontrado tres lugares que especifican dónde se debe evaluar una expresión constexpr durante la traducción.

La sección 3.6.2 Inicialización de variables no locales , el párrafo 2 dice que si un objeto con duración de almacenamiento local estática o de subprocesos se inicializa con un constructor constexpr , el constructor se evalúa durante la traducción:

La inicialización constante se realiza:

  • si un objeto con duración de almacenamiento de subprocesos o estática es inicializado por una llamada del constructor, si el constructor es un constructor constexpr , si todos los argumentos del constructor son expresiones constantes (incluidas las conversiones), y si, después de la sustitución de invocación de función (7.1.5), cada La llamada del constructor y la expresión completa en los inicializadores de mem es una expresión constante;

La sección 7.1.5 El especificador de constexpr , párrafo 9 dice que si una declaración de objeto incluye el especificador de constexpr , ese objeto se evalúa durante la traducción (es decir, es un literal):

Un especificador constexpr utilizado en una declaración de objeto declara que el objeto es const. Dicho objeto tendrá un tipo literal y se inicializará. Si se inicializa mediante una llamada de constructor, esa llamada será una expresión constante (5.19). De lo contrario, cada expresión completa que aparezca en su inicializador será una expresión constante. Cada conversión implícita utilizada para convertir las expresiones de inicialización y cada llamada de constructor utilizada para la inicialización será una de las permitidas en una expresión constante (5.19).

He escuchado a personas argumentar que este párrafo deja espacio para que una implementación posponga la inicialización hasta el tiempo de ejecución, a menos que el efecto se pueda detectar durante la traducción debido, por ejemplo, a static_assert . Probablemente esa no sea una vista precisa, ya que si un valor se inicializa durante la traducción es, en algunas circunstancias, observable. Esta vista está reforzada por la Sección 5.19 Expresiones constantes, párrafo 4:

[ Nota: aunque en algunos contextos las expresiones constantes deben evaluarse durante la traducción del programa, otras pueden evaluarse durante la ejecución del programa. Dado que esta Norma Internacional no impone restricciones a la precisión de las operaciones de punto flotante, no se especifica si la evaluación de una expresión de punto flotante durante la traducción produce el mismo resultado que la evaluación de la misma expresión (o las mismas operaciones en los mismos valores). ) durante la ejecución del programa ... - nota final ]

La Sección 9.4.2 Miembros de datos estáticos , el párrafo 3 dice que si un miembro de datos estáticos const de tipo literal es inicializado por una función o constructor constexpr, entonces esa función o constructor debe evaluarse durante la traducción:

Si un miembro de datos estáticos es de tipo literal const, su declaración en la definición de la clase puede especificar un inicializador con corsé o desigual en el que cada cláusula de inicialización que es una expresión-asignación es una expresión constante. Un miembro de datos estáticos de tipo literal se puede declarar en la definición de clase con el especificador constexpr ; si es así, su declaración especificará un inicializador de corsé o igual en el que cada cláusula de inicialización que sea una expresión-asignación es una expresión constante. [ Nota: En ambos casos, el miembro puede aparecer en expresiones constantes. - nota final ]

Curiosamente, no encontré nada en el FDIS que requiera que se constexpr una expresión constexpr si su resultado se usa como una dimensión de matriz. Estoy bastante seguro de que el comité estándar espera que ese sea el caso. Pero también podría haberme perdido eso en mi búsqueda.

Fuera de estas circunstancias, el estándar C ++ 11 permite realizar cálculos en funciones constexpr y constructores durante la traducción. Pero no lo requiere. Los cálculos podrían ocurrir en tiempo de ejecución. Los cálculos que realiza el compilador durante la traducción son, hasta cierto punto, una cuestión de calidad de implementación.

En las tres situaciones que localicé, el desencadenante para la evaluación del tiempo de traducción se basa en los requisitos del objetivo utilizando el resultado de la llamada constexpr . Nunca se considera si los argumentos de la función constexpr son literales o no (aunque es un requisito previo para una evaluación válida).

Entonces, para llegar al punto real de esto, parece que la evaluación de constexpr durante la traducción se activa mediante:

  • El argumento de objeto implícito durante la resolución de sobrecarga (Sección 13.3.1, Párrafo 3) es constexpr o requiere un literal.

Espero que sea útil para alguien además de mí. Gracias a todos los que contribuyeron.

Solo porque una función (o constructor) ...

  • se declara constexpr y
  • La definición de la función cumple con los requisitos constexpr.

... no significa que el compilador evaluará la función constexpr durante la traducción. He estado mirando a través del C ++ 11 FDIS (N3242, disponible en http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2011/ ) para probar y determinar dos cosas:

  • ¿Cuándo está obligado el compilador a evaluar una función constexpr durante la traducción?
  • ¿Cuándo se le permite al compilador evaluar una función constexpr durante la traducción?

La Sección 5.19 El párrafo 1 dice que las expresiones constantes pueden ser evaluadas durante la traducción. Hasta donde puedo comprender, el resto de la Sección 5.19 establece las reglas para lo que es válido en la definición de una función constexpr.

Entiendo que puedo forzar la evaluación constexpr durante la traducción declarando el resultado de la función constexpr como constexpr. Me gusta esto:

// Declaration constexpr double eulers_num() { return 2.718281828459045235360287471; } // Forced evaluation during translation constexpr double twoEulers = eulers_num() * 2.0; static_assert(twoEulers > 5.0, "Yipes!");

Hasta ahora no he podido encontrar los párrafos en el FDIS que:

  • Forzar a los dos twoEulers a ser evaluados durante la traducción o
  • Especifique otras situaciones en las que el compilador puede o debe evaluar una función constexpr durante la traducción.

Lo que estoy particularmente interesado en descubrir es si la evaluación de constexpr durante la traducción se activa mediante:

  1. Cuando todos los parámetros pasados ​​a la función constexpr son literales, o
  2. El argumento del objeto implícito durante la resolución de sobrecarga (Sección 13.3.1, Párrafo 3) es constexpr o requiere un literal (por ejemplo, para dimensiones de matriz), o
  3. Algo más enteramente.

Por favor, si es posible, en sus respuestas, cite las secciones del FDIS que puedo buscar o las frases clave que puedo buscar en el FDIS. El inglés en la norma es algo obtuso, por lo que es posible que haya estado leyendo los párrafos relevantes y que haya perdido por completo su significado o intención.


Nicol Bolas es 100% correcto, pero hay otro aspecto interesante: si la expresión se evalúa en el momento de la traducción y si se evalúa en el tiempo de ejecución son preguntas completamente independientes. Dado que la expresión constante no puede tener efectos secundarios, puede evaluarse un número arbitrario de veces, y nada impide que se evalúe tanto en tiempo de traducción como en tiempo de ejecución.

Supongamos que la expresión constante fuera una gran matriz (no una std::array , solo una matriz), que es totalmente legal, y el programa no indica que tenga almacenamiento estático. Supongamos también que solo el elemento 7 de la matriz se utiliza en un contexto en el que es necesario el cálculo en tiempo de compilación. Es bastante razonable que el compilador calcule toda la matriz, use el elemento 7, lo descarte e inserte el código para calcularlo en tiempo de ejecución en el ámbito en el que se usa, en lugar de inflar el binario con toda la matriz calculada. Creo que esto no es un tema teórico; Lo he observado con varios compiladores en diversos contextos. constexpr no implica static .

Por supuesto, si el compilador puede determinar que la matriz no se usa en tiempo de ejecución, es posible que ni siquiera inserte el código para calcularlo, pero ese es otro problema.

Si utiliza un objeto de este tipo en tiempo de ejecución, y desea indicar al compilador que valdría la pena mantenerlo durante la duración del programa, debe declararlo como static .


No creo que sea forzado en ningún lado. También eché un vistazo, es complicado porque no hay un solo artículo sobre constexpr en esa lista; todos ellos parecen agregar / quitar de la colección anterior de documentos.

Creo que la idea general es que cuando las entradas a la función constexpr son constexpr mismas, todo se hará en tiempo de compilación; y, por extensión, las declaraciones constexpr que no son de función, que de todos modos son literales, se ejecutarán en tiempo de compilación si está utilizando un compilador medio inteligente.

Si se llama a una función o constructor constexpr con argumentos que no son expresiones constantes, la llamada se comporta como si la función no fuera constexpr, y el valor resultante no es una expresión constante.

de wikipedia

que en parece obtener la información de este pdf :

Funciones constexpr: Una función constexpr es una que es “suficientemente simple” de modo que entrega una expresión constante cuando se llama con argumentos que son valores constantes (ver §2.1).


Se "permite" evaluar la llamada constexpr en el momento de la compilación siempre que sea posible hacerlo. Recuerde que la especificación opera bajo la regla "como si". Entonces, si no puedes notar la diferencia, el compilador puede hacer lo que quiera.

El compilador debe evaluar constexpr llamadas constexpr en tiempo de compilación cuando en realidad necesita la respuesta en tiempo de compilación. Por ejemplo:

constexpr int foo() {return 5;} std::array<float, foo()> arr;

El compilador necesita saber el tamaño de la matriz en el momento de la compilación. Por lo tanto, debe evaluar la expresión constante en tiempo de compilación. Si la función constexpr no se puede ejecutar en tiempo de compilación, se constexpr un error en tiempo de compilación.