В некоторых контекстах требуются выражения, удовлетворяющие дополнительным требованиям, подробно описанным в этом подпункте; другие контексты имеют разную семантику в зависимости от того, удовлетворяет ли выражение этим требованиям. Вызываются выражения, которые удовлетворяют этим требованиям, предполагая, что выполняется копирование constant expressions. [ Note: Постоянные выражения можно оценивать во время перевода. ] — end note
constant-expression: conditional-expression
Выражениеe является a, core constant expression если оценкаe, следуя правиламabstract machine, будет оценивать одно из следующих выражений:
this, за исключением функции constexpr или конструктора constexpr, который оценивается как частьe;
вызов функции, отличной от конструктора constexpr для литерального класса, функции constexpr или неявный вызов тривиального деструктора ([class.dtor]) [ Note:Overload resolution применяется как обычно ]; — end note
вызов неопределенной функции constexpr или неопределенного конструктора constexpr;
вызов созданной функции constexpr или конструктора constexpr, который не удовлетворяет требованиям для функции илиconstexpr конструктора constexpr ;
выражение, которое превзойдетimplementation-defined limits;
операция , которая будет иметь неопределенное поведение , как указано в пунктах[intro] через[cpp] настоящий стандарт [ в Note: том числе, например, целое число со знаком переполнение (раздел[expr]), определенный указателем арифметического ([expr.add]),division by zeroили определенным ];shift operations — end note
lvalue-to-rvalue conversion , если она не применяется к
энергонезависимое значение glvalue целочисленного или перечисляемого типа, которое относится к полному энергонезависимому константному объекту с предшествующей инициализацией, инициализированному константным выражением, или
энергонезависимое значение glvalue, которое относится к подобъекту astring literal, или
энергонезависимое значение glvalue, которое относится к энергонезависимому объекту, определенному с помощьюconstexpr, или которое относится к неизменяемому подобъекту такого объекта, или
энергонезависимое значение glvalue литерального типа, которое относится к энергонезависимому объекту, время жизни которого началось в пределах оценкиe;
объект,lvalue-to-rvalue conversion который применяется к значению glvalue, которое относится к неактивному члену объединения или его подобъекту;
вызов неявно определенного конструктора копирования / перемещения или оператора присваивания копирования / перемещения для объединения, активный член которого (если есть) является изменяемым, если время жизни объекта объединения не началось в пределах оценкиe;
assignment expression или вызов оператора присваивания ([class.copy]) , который изменит активный член союза;
, id-expressionкоторый относится к переменной или элементу данных ссылочного типа, если ссылка не имеет предшествующей инициализации и либо
он инициализируется постоянным выражением или
его время жизни началось в пределах оценкиe;
в a lambda-expression- ссылка наthis или на переменную с автоматической продолжительностью хранения, определенной вне этого lambda-expression, где ссылка будетodr-use; [ Example:
void g() { const int n = 0; [=] { constexpr int i = n; // OK, n is not odr-used and not captured here constexpr int j = *&n; // ill-formed, &n would be an odr-use of n }; }
— end example ] [ Note: Если odr-use происходит при вызове оператора вызова функции закрытого типа, оно больше не ссылаетсяthis на включающую автоматическую переменную из-за преобразования ([expr.prim.lambda.capture]) id-expressionв доступ к соответствующему члену данных. [ Example:
auto monad = [](auto v) { return [=] { return v; }; };
auto bind = [](auto m) {
return [=](auto fvm) { return fvm(m()); };
};
// OK to have captures to automatic objects created during constant expression evaluation.
static_assert(bind(monad(2))(monad)() == monad(2)());
— end example ] ] — end note
преобразование типаcvvoid* в тип указателя на объект;
модификация объекта ([expr.ass],[expr.post.incr], [expr.pre.incr]) , если оно не применяются к энергонезависимому именующему буквальному типу , который ссылается на энергонезависимый объект , чей срок служба начался в оценкеe;
atypeid expression , операнд которого является значением glvalue типа полиморфного класса;
relational илиequality оператора , где результат не определен; или
Еслиe удовлетворяют ограничения выражения основного постоянная, но Оценочноеe будут оценивать операцию , которая имеет неопределенное поведение , как указано в пунктах[library] через[thread] настоящий международный стандарт, это не определенно лиe это выражение ядра постоянная.
[ Example:
int x; // not constant struct A { constexpr A(bool b) : m(b?42:x) { } int m; }; constexpr int v = A(true).m; // OK: constructor call initializes m with the value 42 constexpr int w = A(false).m; // error: initializer for m is x, which is non-constant constexpr int f1(int k) { constexpr int x = k; // error: x is not initialized by a constant expression // because lifetime of k began outside the initializer of x return x; } constexpr int f2(int k) { int x = k; // OK: not required to be a constant expression // because x is not constexpr return x; } constexpr int incr(int &n) { return ++n; } constexpr int g(int k) { constexpr int x = incr(k); // error: incr(k) is not a core constant expression // because lifetime of k began outside the expression incr(k) return x; } constexpr int h(int k) { int x = incr(k); // OK: incr(k) is not required to be a core constant expression return x; } constexpr int y = h(1); // OK: initializes y with the value 2 // h(1) is a core constant expression because // the lifetime of k begins inside h(1)
— end example ]
Anintegral constant expression - это выражение целочисленного типа или типа перечисления с незаданной областью, неявно преобразованное в prvalue, где преобразованное выражение является основным постоянным выражением. [ Note: Такие выражения могут использоваться какbit-field длины, как инициализаторы перечислителя, если базовый тип не является фиксированным ([dcl.enum]), и какalignments. ] — end note
converted constant expression ТипаT представляет собой выражение, неявно преобразован в типT, где преобразованное выражение является выражением постоянная и неявное последовательность преобразования содержит только
определяемые пользователем преобразования,
null pointer conversions изstd::nullptr_t,
null member pointer conversions изstd::nullptr_t, и
и где привязка ссылки (если есть) привязывается напрямую. [ Note: Такие выражения могут использоватьсяnew expressions, какcase expressions, как инициализаторы перечислителя, если базовый тип fixed, какarray границы, так и не типtemplate arguments. ] A - это выражение, где преобразованное выражение является постоянным выражением, а последовательность преобразования содержит только указанные выше преобразования. — end note contextually converted constant expression of type bool contextually converted to bool
Aconstant expression - это либо основное постоянное выражение glvalue, которое относится к сущности, которая является разрешенным результатом константного выражения (как определено ниже), либо основное постоянное выражение prvalue, значение которого удовлетворяет следующим ограничениям:
если значение является объектом типа класса, каждый нестатический член данных ссылочного типа ссылается на сущность, которая является разрешенным результатом константного выражения,
если значение имеет тип указателя, оно содержит адрес объекта со статической продолжительностью хранения, адрес за концом такого объекта ([expr.add]), адрес функции или значение нулевого указателя и
если значение является объектом типа класса или массива, каждый подобъект удовлетворяет этим ограничениям для значения.
Сущность - permitted result of a constant expression это объект со статической продолжительностью хранения, который либо не является временным объектом, либо является временным объектом, значение которого удовлетворяет указанным выше ограничениям, либо это функция.
[ Note: Поскольку настоящий международный стандарт не налагает ограничений на точность операций с плавающей запятой, не указано, дает ли оценка выражения с плавающей запятой во время перевода тот же результат, что и оценка того же выражения (или те же операции над тем же значения) во время выполнения программы.89 [ Example:
bool f() { char array[1 + int(1 + 0.2 - 0.1 - 0.1)]; // Must be evaluated during translation int size = 1 + int(1 + 0.2 - 0.1 - 0.1); // May be evaluated at runtime return sizeof(array) == size; }
Не указано, будет ли значениеf() бытьtrue илиfalse. ] ] — end example — end note
Если выражение литерального типа класса используется в контексте, где требуется интегральное постоянное выражение, то это выражение относится contextually implicitly converted к целочисленному или незадействованному типу перечисления, и выбранная функция преобразования должна бытьconstexpr. [ Example:
struct A { constexpr A(int i) : val(i) { } constexpr operator int() const { return val; } constexpr operator long() const { return 43; } private: int val; }; template<int> struct X { }; constexpr A a = 42; X<a> x; // OK: unique conversion to int int ary[a]; // error: ambiguous conversion
— end example ]
Тем не менее, реализациям рекомендуется обеспечивать согласованные результаты независимо от того, выполнялась ли оценка во время перевода и / или во время выполнения программы.