constexpr (C++)

Ключевое слово constexpr было введено в C++11 и улучшено в C++14. Это означает константное выражение. Например const, его можно применить к переменным: ошибка компилятора возникает, когда любой код пытается изменить значение. В отличие constот этого, constexpr можно также применять к функциям и конструкторам классов. constexpr указывает, что значение или возвращаемое значение является константой и, по возможности, вычисляется во время компиляции.

Целочисленное constexpr значение можно использовать везде const , где требуется целое число, например в аргументах шаблона и объявлениях массива. И когда значение вычисляется во время компиляции вместо времени выполнения, оно помогает программе быстрее выполняться и использовать меньше памяти.

Чтобы ограничить сложность вычислений констант во время компиляции и их потенциальное влияние на время компиляции, стандарт C++14 требует, чтобы типы в константных выражениях были литеральными типами.

Синтаксис

constexpr литеральный типконстант-выражение идентификатора=;
constexpr литеральный типидентификатор { констант-выражение } ;
constexpr литеральный типidentifier(params);
constexpr ctor( params);

Параметры

params
Один или несколько параметров, каждый из которых должен быть литеральным типом и должен быть константным выражением.

Возвращаемое значение

Переменная constexpr или функция должны возвращать литеральный тип.

Переменные constexpr

Основное различие между constconstexpr переменными заключается в том, что инициализация переменной const может быть отложена до времени выполнения. Переменная constexpr должна быть инициализирована во время компиляции. Все constexpr переменные.const

  • Переменная может быть объявлена с constexprпомощью , если она имеет литеральный тип и инициализирована. Если инициализация выполняется конструктором, конструктор должен быть объявлен как constexpr.

  • Ссылка может быть объявлена как constexpr при выполнении обоих этих условий: объект, на который ссылается, инициализируется константным выражением, а любые неявные преобразования, вызываемые во время инициализации, также являются константными выражениями.

  • Все объявления переменной constexpr или функции должны иметь constexpr описатель.

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Функции

constexpr Функция — это функция, возвращаемая значение которой вычислено во время компиляции при использовании кода. Для использования кода требуется возвращаемое значение во время компиляции для инициализации переменной constexpr или для предоставления аргумента шаблона, отличного от типа. Если аргументы являются constexpr значениями, constexpr функция создает константу времени компиляции. При вызове с аргументами, не являющихсяconstexpr аргументами, или если его значение не требуется во время компиляции, оно создает значение во время выполнения, например обычную функцию. (Это двойное поведение сохраняет необходимость записи constexpr и неconstexpr - версий одной функции.)

Функция constexpr или конструктор неявно inline.

Следующие правила применяются к constexpr функциям:

  • Функция constexpr должна принимать и возвращать только литеральные типы.

  • Функция constexpr может быть рекурсивной.

  • До C++20 constexpr функция не может быть виртуальной, и конструктор не может быть определен как constexpr если включаемый класс имеет какие-либо виртуальные базовые классы. В C++20 и более поздних версиях constexpr функция может быть виртуальной. Visual Studio 2019 версии 16.10 и более поздних версий поддерживают constexpr виртуальные функции при указании /std:c++20 или более поздней версии компилятора.

  • Тело может быть определено как = default или = delete.

  • Текст не может содержать goto инструкции или try блоки.

  • Явная специализация шаблона, не являющегося шаблоном,constexpr может быть объявлена следующим образом constexpr:

  • Явная специализация constexpr шаблона также не должна быть constexpr:

Следующие правила применяются к constexpr функциям в Visual Studio 2017 и более поздних версиях:

  • Он может содержать if и switch операторы, а также все операторы цикла, в том числе for, на основе forwhileдиапазона и do-while.

  • Он может содержать объявления локальных переменных, но переменная должна быть инициализирована. Он должен быть литеральным типом и не может быть static локальным или потоком. Локальная объявленная переменная не требуется constи может изменяться.

  • Функция constexpr , неstatic являющейся членом, не требуется неявно 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;
}

Совет

В отладчике Visual Studio при отладке неоптимной сборки отладки можно определить, вычисляется ли constexpr функция во время компиляции, помещая точку останова в нее. Если точка останова достигнута, функция была вызвана во время выполнения. В противном случае функция была вызвана во время компиляции.

наружный constexpr

Параметр компилятора /Zc:externConstexpr приводит к применению внешней компоновки к переменным, объявленным с помощью экстерна constexpr. В более ранних версиях Visual Studio по умолчанию или при указании /Zc:externConstexpr, Visual Studio применяет внутреннюю компоновку к constexpr переменным, даже если используется ключевое extern слово. Параметр /Zc:externConstexpr доступен начиная с Visual Studio 2017 с обновлением 15.6 и отключен по умолчанию. Параметр /permissive- не включает /Zc:externConstexpr.

Пример

В следующем примере показаны constexpr переменные, функции и определяемый пользователем тип. В последней инструкции main()функция-член constexpr является вызовом во время выполнения, GetValue() так как значение не обязательно должно быть известно во время компиляции.

// 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;
}

Требования

Visual Studio 2015 или более поздней версии.

См. также

Объявления и определения
const