constexpr (C++)
La palabra clave constexpr
se introdujo en C++11 y se mejoró en C++14. Significa Expresión constant. Al igual que const
, se puede aplicar a las variables: se produce un error del compilador si algún código intenta modificar el valor. A diferencia de const
, constexpr
también se puede aplicar a los constructors de clase y funciones. constexpr
indica que el valor o el valor devuelto, es constant y, si es posible, se procesará 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 constant en tiempo de compilación y su posible impacto en este tiempo, el estándar de C++14 requiere los tipos en expresiones constant para ser tipos literales.
Sintaxis
constexpr
literal-typeidentifier=constant-expression;
constexpr
literal-typeidentifier{constant-expression};
constexpr
literal-typeidentifier(params);
constexpr
ctor(params);
Parámetros
params
Uno o más parámetros, los cuales deben ser cada uno un tipo literal y deben ser en sí mismos una expresión constant.
Valor devuelto
Una variable o función constexpr
debe devolver un tipo literal.
Variables constexpr
La 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 la inicialización es realizada for por medio de un constructor, el constructor debe declararse comoconstexpr
.Se puede declarar una referencia como
constexpr
cuando se cumplen estas condiciones: el objeto al que se hace referencia se inicializa mediante una expresión constant y las conversiones implícitas invocadas durante la inicialización también son expresiones constant.Todas las declaraciones de una función o variable
constexpr
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 constant 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
constexpr
debe aceptar y devolver únicamente tipos literales.Una función
constexpr
puede ser recursiva.Seafore C++20, una
constexpr
función no puede ser virtual y no se puede definir un constructor comoconstexpr
cuando la clase envolvente tiene ninguna clase base virtual. En C++20 y versiones posteriores, unaconstexpr
función puede ser virtual. Visual Studio 2019, versión 16.10 y versiones posteriores, admitenconstexpr
funciones virtuales cuando se especificaify la/std:c++20
opción del compilador o posterior.El cuerpo se puede definir como
= default
o= delete
.El cuerpo no puede contener instrucciones
goto
ni bloquestry
.Una especialización explícita de una plantilla que no sea
constexpr
no se puede declarar comoconstexpr
:Una especialización explícita de una plantilla
constexpr
no tiene que ser tambiénconstexpr
:
Las reglas siguientes se aplican a las funciones constexpr
de Visual Studio 2017 y versiones posteriores:
Puede contener instrucciones
if
yswitch
, y todas las instrucciones de bucle, incluidasfor
, basadas en intervalosfor
,while
y do-while.Puede contener declaraciones de variables locales, pero la variable debe inicializarse. Debe ser un tipo literal y no puede ser
static
ni local para subprocesos. La variable declarada localmente no es necesaria para serconst
y puede mutar.No es necesario que una función
constexpr
que no sea miembrostatic
sea 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, significa que se llamó a la función en tiempo de ejecución. En caso contrario, significa que 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 /Zc:externConstexpr- especifica, Visual Studio aplica la vinculación interna a las variables constexpr
incluso cuando se usa 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 constexpr
GetValue()
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.
Consulte también
Comentarios
https://aka.ms/ContentUserFeedback.
Próximamente: A lo largo de 2024 iremos eliminando gradualmente GitHub Issues como mecanismo de comentarios sobre el contenido y lo sustituiremos por un nuevo sistema de comentarios. Para más información, vea:Enviar y ver comentarios de