constexpr (C++)
Nyckelordet constexpr
introducerades i C++11 och förbättrades i C++14. Det innebär konstant uttryck. Precis som const
kan den tillämpas på variabler: Ett kompilatorfel utlöses när någon kod försöker ändra värdet. Till skillnad från const
kan constexpr
också tillämpas på funktioner och klasskonstruktorer.
constexpr
anger att värdet, eller returvärdet, är konstant och om möjligt beräknas vid kompileringstillfället.
Ett constexpr
integralvärde kan användas där ett const heltal krävs, till exempel i mallargument och matrisdeklarationer. Och när ett värde beräknas vid kompileringstid i stället för körning hjälper det ditt program att köras snabbare och använda mindre minne.
För att begränsa komplexiteten för kompileringstidskonstanta beräkningar och deras potentiella inverkan på kompileringstiden kräver C++14-standarden att typerna i konstanta uttryck är literaltyper.
Syntax
constexpr
identifierare av literaltyp=konstantuttryck;
constexpr
identifierare av literaltyp{konstantuttryck};
constexpr
identifierare av literaltyp(params);
constexpr
ctor(params);
Parametrar
params
En eller flera parametrar som var och en måste vara en literaltyp och måste vara ett konstant uttryck.
Returvärde
En constexpr
variabel eller funktion måste returnera ett literalt värde av typen.
constexpr variabler
Den primära skillnaden mellan const
och constexpr
variabler är att initieringen av en const
variabel kan skjutas upp till körningstiden. En constexpr
variabel måste initieras vid kompileringen. Alla constexpr
variabler är const
.
En variabel kan deklareras med
constexpr
, när den har en literaltyp och initieras. Om initieringen utförs av en konstruktor måste konstruktorn deklareras somconstexpr
.En referens kan deklareras som
constexpr
när båda dessa villkor uppfylls: Det refererade objektet initieras av ett konstant uttryck, och eventuella implicita konverteringar som anropas under initieringen är också konstanta uttryck.Alla deklarationer av en
constexpr
variabel eller funktion måste haconstexpr
-specificeraren.
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
constexpr funktioner
En constexpr
-funktion är en funktion vars returvärde kan beräknas vid kompileringstid när det efterfrågas av koden. Användning av kod kräver returvärdet vid kompileringstillfället för att initiera en constexpr
-variabel eller för att tillhandahålla ett icke-typ mallargument. När dess argument är constexpr
värden skapar en constexpr
-funktion en kompileringskonstant. När det anropas med argument som inteconstexpr
, eller när dess värde inte krävs vid kompileringstillfället, genererar det ett värde vid körning som en vanlig funktion. (Det här dubbla beteendet sparar dig från att behöva skriva constexpr
och icke-constexpr
versioner av samma funktion.)
En constexpr
funktion eller konstruktor är implicit inline
.
Följande regler gäller för constexpr funktioner:
En
constexpr
-funktion måste endast acceptera och returnera literaltyper.En
constexpr
funktion kan vara rekursiv.Före C++20 kan en
constexpr
-funktion inte vara virtuella, och en konstruktor kan inte definieras somconstexpr
när den omslutande klassen har några virtuella basklasser. I C++20 och senare kan enconstexpr
funktion vara virtuell. Visual Studio 2019 version 16.10 och senare versioner stöderconstexpr
virtuella funktioner när du anger alternativet/std:c++20
eller senare kompilator.Kroppen kan definieras som
= default
eller= delete
.Textkroppen får inte innehålla några
goto
-instruktioner ellertry
-block.En explicit specialisering av en mall som inte är
constexpr
kan deklareras somconstexpr
:En explicit specialisering av en
constexpr
mall behöver inte heller varaconstexpr
:
Följande regler gäller för constexpr
funktioner i Visual Studio 2017 och senare:
Den kan innehålla
if
- ochswitch
-uttryck samt alla loop-satser, inklusivefor
, intervallbaseradefor
,while
och do-while.Den kan innehålla lokala variabeldeklarationer, men variabeln måste initieras. Det måste vara en literaltyp och får inte vara
static
eller trådlokal. Den lokalt deklarerade variabeln måste inte varaconst
och kan mutera.En
constexpr
icke-static
medlemsfunktion behöver inte vara implicitconst
.
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;
}
Tips
När du felsöker en icke-optimerad felsökningsversion i Visual Studio-felsökningsprogrammet kan du se om en constexpr
funktion utvärderas vid kompileringstidpunkten genom att placera en brytpunkt i den. Om brytpunkten träffas anropades funktionen under körning. Annars anropades funktionen vid kompileringstillfället.
extern constexpr
Alternativet /Zc:externConstexpr kompilator gör att kompilatorn tillämpar extern länkning på variabler som deklareras med hjälp av extern constexpr. I tidigare versioner av Visual Studio, antingen som standard eller när /Zc:externConstexpr– anges, tillämpar Visual Studio intern länkning på constexpr
variabler även när nyckelordet extern
används. Alternativet /Zc:externConstexpr är tillgängligt från och med Visual Studio 2017 Update 15.6 och är inaktiverat som standard. Alternativet /permissive- aktiverar inte /Zc:externConstexpr.
Exempel
I följande exempel visas constexpr
variabler, funktioner och en användardefinierad typ. I den sista instruktionen i main()
är funktionen constexpr
medlem GetValue()
ett körningsanrop eftersom värdet inte krävs för att vara känt vid kompileringstillfället.
// 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;
}
Krav
Visual Studio 2015 eller senare.