Nota:
El acceso a esta página requiere autorización. Puede intentar iniciar sesión o cambiar directorios.
El acceso a esta página requiere autorización. Puede intentar cambiar los directorios.
La palabra clave constexpr se introdujo en C++11 y se mejoró en C++14. Significa expresión constante. Igual que const, se puede aplicar a variables: se genera un error del compilador cuando cualquier código intenta modificar el valor. A diferencia de const, constexpr también se puede aplicar a funciones y constructores de clases.
constexpr Indica que el valor, o valor devuelto, es constante y, cuando es posible, se calcula en tiempo de compilación.
Un valor entero constexpr se puede usar donde se requiera un entero const, como es el caso de las declaraciones de matrices y los argumentos de plantillas. Y si un valor se procesa en tiempo de compilación en lugar de en tiempo de ejecución, ayuda a su programa a ejecutarse más rápidamente y a usar menos memoria.
Para limitar la complejidad de los cálculos de constantes en tiempo de compilación y sus posibles impactos en el tiempo de compilación, el estándar C++14 requiere que los tipos de las expresiones constantes sean tipos literales.
Sintaxis
constexprliteral-typeidentifier=constant-expression;
constexprliteral-typeidentifier{constant-expression};
constexprliteral-typeidentifier(params);
constexprctor(params);
Parámetros
params
Uno o más parámetros, cada uno de los cuales debe ser un tipo literal y debe ser a su vez una expresión constante.
Valor devuelto
Una variable o función constexpr debe devolver un tipo literal.
Variables constexpr
La principal diferencia entre las variables const y constexpr es que la inicialización de una variable const se puede aplazar hasta el tiempo de ejecución. Una variable constexpr se debe inicializar en tiempo de compilación. Todas las variables constexpr son const.
Una variable se puede declarar con
constexpr, si tiene un tipo literal y está inicializada. Si un constructor realiza la inicialización, el constructor debe declararse comoconstexpr.Una referencia puede declararse como
constexprsi se cumplen estas dos condiciones: el objeto al que hace referencia se inicializa mediante una expresión constante y todas las conversiones implícitas que se invoquen durante la inicialización son también expresiones constantes.Todas las declaraciones de una variable
constexpro función deben tener el especificadorconstexpr.
constexpr float x = 42.0;
constexpr float y{108};
constexpr float z = exp(5, 3);
constexpr int i; // Error! Not initialized
int j = 0;
constexpr int k = j + 1; //Error! j not a constant expression
funcionesconstexpr
Una función constexpr es aquella cuyo valor devuelto se calcula durante el tiempo de compilación cuando el código usado lo requiere. El código de consumo requiere el valor de retorno en tiempo de compilación para inicializar una variable constexpr o proporcionar un argumento de plantilla que no sea de tipo. Cuando sus argumentos son valores constexpr, una función constexpr genera una constante en tiempo de compilación. Cuando se llama con argumentos que no sean constexpr o cuando su valor no se requiere en tiempo de compilación, genera un valor en tiempo de ejecución como una función normal. (Este doble comportamiento le evita tener que escribir tanto versiones constexpr como las que no sean constexpr de la misma función).
Una función constexpr o constructor es implícitamente inline.
Las reglas siguientes se aplican a las funciones constexpr:
Una función
constexprdebe aceptar y devolver únicamente tipos literales.Una función
constexprpuede ser recursiva.Antes de C++20, una función
constexprno podía ser virtual y un constructor no se podía definir comoconstexprcuando la clase envolvente tenía clases de base virtual. En C++20 y versiones posteriores, una funciónconstexprpuede ser virtual. Visual Studio 2019, versión 16.10 y versiones posteriores admiten funciones virtualesconstexprcuando se especifica la opción del compilador/std:c++20o posterior.El cuerpo se puede definir como
= defaulto= delete.El cuerpo no puede contener instrucciones
gotoni bloquestry.Una especialización explícita de una plantilla que no sea
constexprno se puede declarar comoconstexpr:Una especialización explícita de una plantilla
constexprno tiene que ser tambiénconstexpr:
Las reglas siguientes se aplican a las funciones constexpr de Visual Studio 2017 y versiones posteriores:
Puede contener instrucciones
ifyswitch, y todas las instrucciones de bucle, incluidasfor, basadas en intervalosfor,whiley do-while.Puede contener declaraciones de variables locales, pero la variable debe inicializarse. Debe ser un tipo literal y no puede ser
staticni local para subprocesos. La variable declarada localmente no es necesaria para serconsty puede mutar.No es necesario que una función
constexprque no sea miembrostaticsea implícitamenteconst.
constexpr float exp(float x, int n)
{
return n == 0 ? 1 :
n % 2 == 0 ? exp(x * x, n / 2) :
exp(x * x, (n - 1) / 2) * x;
}
Sugerencia
En el depurador de Visual Studio, al depurar una compilación de depuración no optimizada, puede indicar si una función constexpr se evalúa en tiempo de compilación colocando un punto de interrupción en su interior. Si se alcanza el punto de interrupción, se llamó a la función en tiempo de ejecución. Si no es así, se llamó a la función en tiempo de compilación.
constexpr externo
La opción del compilador /Zc:externConstexpr hace que el compilador aplique la vinculación externa a las variables declaradas mediante constexpr externo. En versiones anteriores de Visual Studio, ya sea de forma predeterminada o cuando se especificaba /Zc:externConstexpr-, Visual Studio aplicaba la vinculación interna a las variables constexpr incluso cuando se usaba la palabra clave extern. La opción /Zc:externConstexpr está disponible a partir de la actualización 15.6 de Visual Studio 2017 y está desactivada de forma predeterminada. La opción /permissive- no habilita /Zc:externConstexpr.
Ejemplo
En el siguiente ejemplo se muestran las variables constexpr, las funciones y un tipo definido por usuario. En la última instrucción en main(), la función miembro constexprGetValue() es una llamada en tiempo de ejecución porque no es necesario conocer el valor en tiempo de compilación.
// constexpr.cpp
// Compile with: cl /EHsc /W4 constexpr.cpp
#include <iostream>
using namespace std;
// Pass by value
constexpr float exp(float x, int n)
{
return n == 0 ? 1 :
n % 2 == 0 ? exp(x * x, n / 2) :
exp(x * x, (n - 1) / 2) * x;
}
// Pass by reference
constexpr float exp2(const float& x, const int& n)
{
return n == 0 ? 1 :
n % 2 == 0 ? exp2(x * x, n / 2) :
exp2(x * x, (n - 1) / 2) * x;
}
// Compile-time computation of array length
template<typename T, int N>
constexpr int length(const T(&)[N])
{
return N;
}
// Recursive constexpr function
constexpr int fac(int n)
{
return n == 1 ? 1 : n * fac(n - 1);
}
// User-defined type
class Foo
{
public:
constexpr explicit Foo(int i) : _i(i) {}
constexpr int GetValue() const
{
return _i;
}
private:
int _i;
};
int main()
{
// foo is const:
constexpr Foo foo(5);
// foo = Foo(6); //Error!
// Compile time:
constexpr float x = exp(5, 3);
constexpr float y { exp(2, 5) };
constexpr int val = foo.GetValue();
constexpr int f5 = fac(5);
const int nums[] { 1, 2, 3, 4 };
const int nums2[length(nums) * 2] { 1, 2, 3, 4, 5, 6, 7, 8 };
// Run time:
cout << "The value of foo is " << foo.GetValue() << endl;
}
Requisitos
Visual Studio 2015 o posterior.