Udostępnij przez


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 constklasy 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

constexprwyrażenie-wcięcieif typu literału ier=const;
constexpridentif typuliterału{constwyrażenie-ant};
constexprierif(params);
constexprctor(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ą constexprmetody , gdy ma typ literału i jest inicjowana. Jeśli inicjowanie jest naformed przez constructor, constructor musi być zadeklarowany jako constexpr.

  • 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, jak constexpr w przypadku, gdy otaczającej klasy ma żadnych wirtualnych klas bazowych. W języku C++20 lub nowszym funkcja może być wirtualna constexpr . Program Visual Studio 2019 w wersji 16.10 lub nowszej obsługuje constexpr 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 ani try bloków.

  • Jawna specjalizacja szablonu innego niżconstexpr szablon można zadeklarować jako constexpr:

  • 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 i switch oraz wszystkie instrukcje pętli, w tym for, oparte na forzakresie , whilei 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 do constwartości i może być mutacja.

  • Funkcja constexpr niezwiązanastatic z elementem członkowskim nie musi być niejawnie const.

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ż

Deklaracje i definicje
const