constexpr (C++)
A palavra-chave constexpr
foi introduzida em C++11 e aprimorada em C++14. Ela significa expressão constante. Como const
, ela pode ser aplicada a variáveis: um erro do compilador é gerado quando qualquer código tenta modificar o valor. Ao contrário de const
, constexpr
também pode ser aplicado a funções e construtores de classe. constexpr
indica que o valor, ou valor retornado, é constante e, sempre que possível, é calculado em tempo de compilação.
Um valor integral constexpr
pode ser usado sempre que um inteiro const for necessário, como em argumentos de modelo e declarações de matriz. Quando um valor é calculado em tempo de compilação em vez de em tempo de execução, ele ajuda seu programa a executar mais rapidamente e usar menos memória.
Para limitar a complexidade de computações constantes em tempo de compilação e seus impactos potenciais sobre o tempo de compilação, o padrão C++14 exige que os tipos em expressões constantes sejam tipos literais.
Sintaxe
constexpr
literal-typeidentifier=constant-expression;
constexpr
literal-typeidentifier{constant-expression};
constexpr
literal-typeidentifier(params);
constexpr
ctor(params);
Parâmetros
params
Um ou mais parâmetros, cada um deles deve ser um tipo literal e deve ser uma expressão constante.
Retornar valor
Uma variável ou função constexpr
deve retornar um tipo literal.
Variáveis constexpr
A principal differença entre variáveis const
e constexpr
é que a inicialização de uma variável const
pode ser adiada até o tempo de execução. Uma variável constexpr
deve ser inicializada em tempo de compilação. Todas as variáveis constexpr
são const
.
Uma variável pode ser declarada com
constexpr
quando tem um tipo literal e é inicializada. Se a inicialização for formada por um construtor, o construtor deverá ser declarado comoconstexpr
.Uma referência pode ser declarada como
constexpr
quando ambas as condições são atendidas: o objeto referenciado é inicializado por uma expressão consttante e todas as conversões implícitas invocadas durante a inicialização também são expressões consttantes.Todas as declarações de uma variável
constexpr
ou função devem ter o 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
Funções constexpr
Uma função constexpr
é aquela cujo valor retornado é computável em tempo de compilação quando o código de consumo exige isso. O código de consumo requer o valor retornado em tempo de compilação para inicializar uma variável constexpr
ou para fornecer um argumento não de modelo de tipo. Quando seus argumentos são valores constexpr
, uma função constexpr
produz uma constante em tempo de compilação. Quando chamado com argumentos não constexpr
ou quando seu valor não é necessário em tempo de compilação, é gerado um valor em tempo de execução como uma função regular. (Esse comportamento duplo poupa você de escrever versões constexpr
e não constexpr
da mesma função.)
Uma função ou construtor constexpr
é implicitamente inline
.
As seguintes regras se aplicam a funções constexpr:
Uma função
constexpr
deve aceitar e retornar apenas tipos literais.Uma função
constexpr
pode ser recursiva.Before C++20, uma
constexpr
função não pode ser virtual, e um constructor não pode ser definido comoconstexpr
quando a classe de fechamento tem qualquer classe base virtual. No C++20 e posterior, umaconstexpr
função pode ser virtual. Visual Studio 2019 versão 16.10 e versões posteriores oferecem suporte a funções virtuais quando você especificaify aconstexpr
opção de/std:c++20
compilador ou posterior.O corpo pode ser definido como
= default
ou= delete
.O corpo pode não conter instruções
goto
ou blocostry
.Uma especialização explícita de um modelo não
constexpr
pode ser declarada comoconstexpr
:Uma especialização explícita de um modelo
constexpr
também não precisa serconstexpr
:
As seguintes regras se aplicam a funções constexpr
no Visual Studio 2017 e posteriores:
Ela pode conter instruções
if
eswitch
e todas as instruções de loop, incluindofor
,for
baseadas em intervalo,while
e do-while.Pode conter declarações de variáveis locais, mas a variável deve ser inicializada. Deve ser um tipo literal e não pode ser
static
ou thread-local. A variável declarada localmente não precisa serconst
e pode sofrer mutação.Uma função de membro não
static
constexpr
não precisa ser implicitamenteconst
.
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;
}
Dica
No depurador do Visual Studio, ao depurar um build de depuração não otimizado, você pode determinar se uma função constexpr
está sendo avaliada no tempo de compilação colocando um ponto de interrupção dentro dela. Se o ponto de interrupção for atingido, a função foi chamada em tempo de execução. Caso contrário, a função foi chamada em tempo de compilação.
extern constexpr
A opção do compilador /Zc:externConstexpr faz com que o compilador aplique o vínculo externo a variáveis declaradas usando extern constexpr. Em versões anteriores do Visual Studio, por padrão ou quando /Zc:externConstexpr- é especificado, o Visual Studio aplica o vínculo interno a variáveis constexpr
mesmo quando a palavra-chave extern
é usada. A opção /Zc:externConstexpr está disponível no Visual Studio 2017 atualização 15.6 em diante e está desativada por padrão. A opção /permissive- não habilita /Zc:externConstexpr.
Exemplo
O exemplo a seguir mostra variáveis constexpr
, funções e um tipo definido pelo usuário. Na última instrução em main()
, a função de membro constexpr
GetValue()
é uma chamada em tempo de execução porque o valor não precisa ser conhecido em tempo de compilação.
// 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 ou posterior.
Confira também
Comentários
https://aka.ms/ContentUserFeedback.
Brevemente: Ao longo de 2024, vamos descontinuar progressivamente o GitHub Issues como mecanismo de feedback para conteúdos e substituí-lo por um novo sistema de feedback. Para obter mais informações, veja:Submeter e ver comentários