constexpr (C++)

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

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

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

Синтаксис

constexprлитеральный типidentifier=constant-expression;
constexprидентификатор типаifлитерала ier{constant-expression};
constexprлитеральный типidentifier(params);
constexprctor(params);

Параметры

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

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

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

Переменные constexpr

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

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

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

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

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 функция создает ант времени constкомпиляции. При вызове с аргументами, не являющихсяconstexpr аргументами, или если его значение не требуется во время компиляции, оно создает значение во время выполнения, например обычную функцию. (Это двойное поведение сохраняет необходимость записи constexpr и неconstexpr - версий одной функции.)

Функция constexpr или constructor неявно inline.

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

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

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

  • Будьтеfore C++20, constexpr функция не может быть виртуальной, и constруттор не может быть определен как constexpr если включаемый класс имеет какие-либо виртуальные базовые классы. В C++20 и более поздних версиях constexpr функция может быть виртуальной. Visual Studio 2019 версии 16.10 и более поздних версий поддерживают constexpr виртуальные функции при спецификацииif/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 функция во время компиляции, помещая точку останова в нее. Попадание в точку останова означает, что функция была вызвана во время выполнения. Если попадания в точку останова не происходит, это означает, что функция была вызвана во время компиляции.

Extern constexpr

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

Пример

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

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