Примечание.
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
Ключевое слово constexpr было введено в C++11 и улучшено в C++14. Это означает константное выражение. Например const, его можно применить к переменным: ошибка компилятора возникает, когда любой код пытается изменить значение. В отличие constот этого, constexpr можно также применять к функциям и конструкторам классов.
constexpr указывает, что значение или возвращаемое значение является константой и, по возможности, вычисляется во время компиляции.
Целочисленное constexpr значение можно использовать везде const , где требуется целое число, например в аргументах шаблона и объявлениях массива. И когда значение вычисляется во время компиляции вместо времени выполнения, оно помогает программе быстрее выполняться и использовать меньше памяти.
Чтобы ограничить сложность вычислений констант во время компиляции и их потенциальное влияние на время компиляции, стандарт C++14 требует, чтобы типы в константных выражениях были литеральными типами.
Синтаксис
constexprлитеральный типконстант-выражение идентификатора=;
constexprлитеральный типидентификатор { констант-выражение } ;
constexprлитеральный типidentifier(params);
constexprctor( 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 или более поздней версии.