constexpr (C++)
Słowo kluczowe constexpr
zostało wprowadzone w języku C++11 i ulepszone w języku C++14. constOznacza to wyrażenie mrówek. Podobnie jak const
, można go zastosować do zmiennych: błąd kompilatora jest zgłaszany, gdy dowolny kod próbuje modowaćifwartość. W przeciwieństwie do const
klasy można constexpr
również stosować do funkcji i ructorów klas const. constexpr
wskazuje, że wartość lub wartość zwracana jest constant i, jeśli to możliwe, jest obliczana w czasie kompilacji.
Wartość constexpr
całkowita może być używana wszędzie tam const , gdzie wymagana jest liczba całkowita, na przykład w argumentach szablonu i deklaracjach tablicy. A gdy wartość jest obliczana w czasie kompilacji zamiast czasu wykonywania, pomaga program działać szybciej i używać mniejszej ilości pamięci.
Aby ograniczyć złożoność obliczeń w czasie constkompilacji i ich potencjalny wpływ na czas kompilacji, standard C++14 wymaga typów w constwyrażeniach mrówek jako typów literałów.
Składnia
constexpr
wyrażenie-wcięcieif typu literału ier=const;
constexpr
identif typuliterału{constwyrażenie-ant};
constexpr
ierif(params);
constexpr
ctor(params);
Parametry
params
Co najmniej jeden parametr, z których każdy musi być typem literału i musi być wyrażeniem constant.
Wartość zwracana
Zmienna constexpr
lub funkcja musi zwracać typ literału.
constexpr Zmiennych
Podstawowa ference difmiędzy zmiennymi const
i constexpr
polega na tym, że inicjowanie zmiennej const
można odroczyć do czasu wykonywania. Zmienna constexpr
musi być inicjowana w czasie kompilacji. Wszystkie constexpr
zmienne to const
.
Zmienną można zadeklarować za pomocą
constexpr
metody , gdy ma typ literału i jest inicjowana. Jeśli inicjowanie jest naformed przez constructor, constructor musi być zadeklarowany jakoconstexpr
.Odwołanie może być zadeklarowane tak, jak
constexpr
w przypadku spełnienia obu tych warunków: obiekt, do którego odwołuje się wyrażenie constant, a wszelkie niejawne konwersje wywoływane podczas inicjowania są również constwyrażeniami mrówek.Wszystkie deklaracje zmiennej
constexpr
lub funkcji muszą mieć specyfikacjęifconstexpr
ier.
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, funkcje
Funkcja jest funkcją constexpr
, której wartość zwracana jest komputable w czasie kompilacji, gdy wymaga jej użycie. Korzystanie z kodu wymaga wartości zwracanej w czasie kompilacji constexpr
w celu zainicjowania zmiennej lub podania argumentu szablonu innego niż typ. Gdy jej argumenty są constexpr
wartościami, constexpr
funkcja generuje skompilowany element mrówek czasu constkompilacji. Gdy jest wywoływana z argumentami innym niżconstexpr
argumenty lub gdy jej wartość nie jest wymagana w czasie kompilacji, generuje wartość w czasie wykonywania, jak zwykła funkcja. (To podwójne zachowanie pozwala zaoszczędzić na konieczności zapisu constexpr
i innychconstexpr
wersji tej samej funkcji).
Funkcja constexpr
lub constructor jest niejawnie inline
.
Następujące reguły dotyczą constexpr funkcji:
constexpr
Funkcja musi akceptować i zwracać tylko typy literałów.Funkcja
constexpr
może być rekursywna.Byćfore C++20,
constexpr
funkcja nie może być wirtualna, a constructor nie może być zdefiniowany tak, jakconstexpr
w przypadku, gdy otaczającej klasy ma żadnych wirtualnych klas bazowych. W języku C++20 lub nowszym funkcja może być wirtualnaconstexpr
. Program Visual Studio 2019 w wersji 16.10 lub nowszej obsługujeconstexpr
funkcje wirtualne po wybraniuifopcji kompilatora lub nowszego/std:c++20
.Treść można zdefiniować jako
= default
lub= delete
.Treść nie
goto
może zawierać żadnych instrukcji anitry
bloków.Jawna specjalizacja szablonu innego niż
constexpr
szablon można zadeklarować jakoconstexpr
:Jawna specjalizacja szablonu
constexpr
nie musi być również :constexpr
Następujące reguły dotyczą constexpr
funkcji w programie Visual Studio 2017 i nowszych wersjach:
Może zawierać
if
instrukcje iswitch
oraz wszystkie instrukcje pętli, w tymfor
, oparte nafor
zakresie ,while
i do-while.Może zawierać deklaracje zmiennych lokalnych, ale zmienna musi zostać zainicjowana. Musi być typem literału i nie może być
static
ani wątkowo-lokalny. Lokalnie zadeklarowana zmienna nie jest wymagana doconst
wartości i może być mutacja.Funkcja
constexpr
niezwiązanastatic
z elementem członkowskim nie musi być niejawnieconst
.
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;
}
Napiwek
W debugerze programu Visual Studio podczas debugowania nieoptymalizowanej kompilacji debugowania można określić, czy constexpr
funkcja jest oceniana w czasie kompilacji, umieszczając wewnątrz niej punkt przerwania. Jeśli punkt przerwania zostanie trafiony, funkcja została wywołana w czasie wykonywania. Jeśli nie, funkcja została wywołana w czasie kompilacji.
Extern constexpr
Opcja kompilatora /Zc:externConstexpr powoduje, że kompilator stosuje połączenie zewnętrzne do zmiennych zadeklarowanych przy użyciu extern constexpr. We wcześniejszych wersjach programu Visual Studio domyślnie lub gdy /Zc:externConstexpr — jestifspecyfikacją, program Visual Studio stosuje wewnętrzne powiązania ze constexpr
zmiennymi nawet wtedy, gdy extern
słowo kluczowe jest używane. Opcja /Zc:externConstexpr jest dostępna począwszy od programu Visual Studio 2017 Update 15.6 i jest domyślnie wyłączona. Opcja /permissive- nie włącza /Zc:externConstexpr.
Przykład
W poniższym przykładzie przedstawiono constexpr
zmienne, funkcje i typ zdefiniowany przez użytkownika. W ostatniej instrukcji w elemencie main()
funkcja GetValue()
składowa constexpr
jest wywołaniem czasu wykonywania, ponieważ wartość nie jest wymagana, aby być znana w czasie kompilacji.
// 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;
}
Wymagania
Program Visual Studio 2015 lub nowszy.
Zobacz też
Opinia
https://aka.ms/ContentUserFeedback.
Dostępne już wkrótce: W 2024 r. będziemy stopniowo wycofywać zgłoszenia z serwisu GitHub jako mechanizm przesyłania opinii na temat zawartości i zastępować go nowym systemem opinii. Aby uzyskać więcej informacji, sprawdź:Prześlij i wyświetl opinię dla