and c++ c++11 constexpr

c++ - and - ¿Constexpr es una "sugerencia"(como en línea) o "una solicitud de enlace" para el compilador?



constexpr in c++ (4)

¿ constexpr es una "sugerencia" (como en línea) o "una solicitud de enlace" para el compilador?

No es ninguno. Olvídate de cuando se evalúa. Todo (con unas pocas excepciones menores, especialmente las que involucran volatile ) se evalúa siempre que el compilador considere necesario producir el comportamiento de la máquina abstracta de C ++. No hay mucho más que decir sobre cuándo se evalúan las cosas.

El compilador es libre de producir código que evalúe lo que serían expresiones constantes en tiempo de ejecución si eso no produce un comportamiento diferente. Es libre de producir código que evalúe las cosas que no están marcadas como constexpr en tiempo de compilación si tiene la inteligencia.

Si no se trata de tiempo de compilación frente a tiempo de ejecución, ¿de qué trata constexpr , entonces?

constexpr permite que las cosas sean tratadas como expresiones constantes. Cualquier cosa marcada como constexpr debe tener la posibilidad de producir una expresión constante de alguna manera.

En el caso de las funciones, pueden producir expresiones constantes con algunos argumentos pero no con otros. Pero siempre que haya algún conjunto de argumentos que puedan dar como resultado una expresión constante, una función puede marcarse como constexpr . Si ese conjunto de argumentos se usa en una llamada a una función, esa expresión es una expresión constante. ¿Significa eso que se evalúa en tiempo de compilación? Véase más arriba. Se evalúa cuando el compilador lo juzga apropiado. Lo único que significa es que puedes usarlo en un contexto que requiera una expresión constante.

Para las variables, sean expresiones constantes o no. No tienen argumentos, por lo que si constexpr siempre tienen que inicializarse con expresiones constantes.

TL; DR : constexpr se trata de etiquetar cosas como usables en expresiones constantes, no de decidir cuándo evaluarlas.

Con eso fuera del camino, parece que su plantilla de función está mal formada. No hay un conjunto de argumentos que puedan dar como resultado una expresión constante. Sin embargo, el estándar no requiere un diagnóstico para esto.

¿ constexpr es un indicador para el compilador o constexpr un comportamiento?

El ejemplo que nos ocupa es el siguiente:

template<typename T> std::size_t constexpr getID() { return typeid(T).hash_code(); }

hash_code es una constante de tiempo de ejecución, pero este fragmento de hash_code se compile aunque se solicite una evaluación de tiempo de compilación con constexpr . Solo después de que se use el valor de retorno donde se espera una constante de tiempo de compilación, nos daremos cuenta de que esto no se puede utilizar como una función constexpr .

Entonces, ¿es constexpr una "sugerencia" (como la palabra clave en inline ) o "una solicitud de enlace" al compilador?


Desde la página de C ++ 11 Wiki :

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. Del mismo modo, si la expresión en la declaración de retorno de una función constexpr no se evalúa como una expresión constante para una invocación particular, el resultado no es una expresión constante.

El especificador constexpr expresa así la posibilidad de evaluar algo en tiempo de compilación y está sujeto a algunas restricciones cuando se usa.

Para su fragmento particular, me parece que la restricción de C ++ 11:

exactamente una declaración de retorno que contiene solo valores literales, variables constexpr y funciones

no se cumple, como hash_code se define como:

size_t hash_code() const;

En este caso el borrador estándar n3242 dice:

Para una función constexpr, si no existen valores de argumento de función tales que la sustitución de invocación de la función produzca una expresión constante (5.19), el programa está mal formado; no requiere diagnóstico

Creo que su ejemplo encaja aquí.


La respuesta completa a su pregunta tiene dos aspectos:

  1. Una función constexpr solo se puede evaluar en tiempo de compilación cuando todos los argumentos se pueden evaluar en tiempo de compilación. Todavía se puede utilizar como una función normal que se evalúa en tiempo de ejecución.

  2. Una variable constexpr debe inicializarse con un valor evaluado en tiempo de compilación. El compilador tiene que generar un error si no puede hacer esto.

Podría asignar el código hash a una variable constexpr y luego obtener una salida del compilador:

#include <typeinfo> #include <array> template<typename T> std::size_t constexpr getID() { return []() {constexpr size_t id = typeid(T).hash_code(); return id;}(); } int main() { // both statement generate compiler errors //std::array<int, typeid(int).hash_code()> a; //constexpr size_t y = typeid(int).hash_code(); size_t x = getID<int>(); }


Las funciones constexpr pueden usarse para evaluar constantes de tiempo de compilación. Así que es posible usarlo como:

constexpr int func(int a) { return a+2; } char x[func(10)];

Si se llama a func durante el tiempo de ejecución, el compilador puede evaluar esta expresión antes si es posible. Pero eso no es obligatorio, pero normalmente se hace si la entrada también es constante.

También es importante tener constexpr constructores. Esta es la única oportunidad de obtener clases no POD de objetos constexpr.

class Point { private: int x; int y; public: constexpr Point( int _x, int _y) : x(_x), y(_y) {} constexpr int GetX() const { return x; } }; constexpr Point p{1,2}; int main() { char i[p.GetX()]; return 0; }