c++ constexpr
¿Qué es constexpr en C++? (4)
Estoy realmente confundido acerca de un concepto constexpr
, ya que he leído que constexpr
se evalúa en el momento de la compilación, por lo que es útil para la optimización del rendimiento en comparación con la const
normal.
constexpr int i = 0;
constexpr int& ri = i;
El código anterior devuelve un error "inicialización de referencia no válida de tipo ''int &'' de la expresión de tipo ''const int''", ¿por qué?
Además, el siguiente código tiene un error:
constexpr int i = 0;
constexpr int* ri = &i;
Si reemplacé la palabra clave constexpr
con const
, todo lo anterior funcionó correctamente.
Aquí están mis 2 centavos:
La característica constexpr
define el cálculo que ocurre durante el tiempo de compilación. Pregunta razonable:
- ¿Tiene sentido permitir cualquier cálculo ?
Respuesta razonable:
- No , porque esto requeriría una gran cantidad de maquinaria, recursos, etc., justo dentro del compilador, mientras que no hay necesidad directa de eso.
Debido a que el estándar permite un conjunto bastante limitado de características dentro del código constexpr
. Uno puede discutir por qué exactamente este conjunto y no algo más? Bueno, más adelante el estándar puede evolucionar y permitir más.
Como dijiste, constexpr
se evalúa en tiempo de compilación . Así que el valor debe ser evaluable al compilar.
Por ejemplo:
constexpr int i = 0;
constexpr int& ri = i;
Para la primera línea, 0 es evaluable al compilar, su valor es 0.
Pero para la segunda línea, el compilador necesita la dirección de i
para realizar la asignación, que se determina en el tiempo de ejecución. Así que esta línea va a fallar.
Re
" Si sustituí la palabra constexpr con const, todo funcionó correctamente".
A const int*
significa esencialmente (const int)*
, excepto que no puede usar paréntesis de esa manera. Un constexpr int*
significa constepxr (int*)
(ídem).
Esto se debe a que constexpr
no es parte del tipo, no puede nombrar el tipo constexpr int
, por ejemplo, mientras que const
es parte del tipo.
En lugar de
constexpr int i = 0;
constexpr int& ri = i;
que intenta declarar una referencia constexpr
a no const
, simplemente escriba
constexpr int i = 0;
constexpr int const& ri = i;
Puede leer que al revés ya que ri
es una referencia a una const
que es constexpr
(evaluada en tiempo de compilación).
Anexo :
Aparece que C ++ 14 requiere que los objetos constexpr
locales no static
tengan una duración de almacenamiento automática , módulo la regla de optimización de if-if .
Para atender esto, es decir, para hacer que el código sea portátil en los compiladores, si las declaraciones anteriores aparecen localmente en una función, agregue static
para asegurar la duración del almacenamiento estático para el objeto al que se hace referencia:
void oops()
{
static constexpr int i = 0; // Necessary with some compilers.
constexpr int const& ri = i;
}
De lo contrario, es posible que no se compile con, por ejemplo, g ++, y es probablemente lo que requieren los estándares C ++ 14 y C ++ 11, por omisión de restricciones adecuadas en constexpr
.
Notas:
¹ Ver la discusión de la respuesta de R. Sahu .
constexpr int i = 0;
constexpr int * ri = &i;
La segunda línea es un problema porque el puntero no apunta a un objeto const
. El puntero en sí es const
.
Utilizando
constexpr int i = 0;
constexpr int const * ri = &i;
resuelve ese problema Sin embargo, eso seguirá siendo un problema si las variables se definen en un ámbito de función.
constexpr int i = 0;
constexpr int const* ri = &i;
int main() {}
Es un programa válido.
void foo()
{
constexpr int i = 0;
constexpr int const* ri = &i;
}
int main() {}
no es un programa valido
Esto es lo que el estándar C ++ 11 tiene que decir acerca de la expresión de la constante de dirección :
5.19 expresiones constantes
3. Una expresión de constante de dirección es una expresión de constante de núcleo de valor nominal de tipo puntero que se evalúa a la dirección de un objeto con una duración de almacenamiento estático, a la dirección de una función, a un valor de puntero nulo, o una expresión de constante de núcleo de valor predeterminado de escribe
std::nullptr_t
.