8 Expressions [expr]

8.20 Constant expressions [expr.const]

В некоторых контекстах требуются выражения, удовлетворяющие дополнительным требованиям, подробно описанным в этом подпункте; другие контексты имеют разную семантику в зависимости от того, удовлетворяет ли выражение этим требованиям. Вызываются выражения, которые удовлетворяют этим требованиям, предполагая, что выполняется копирование 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* в тип указателя на объект;

  • аdynamic cast;

  • аreinterpret_­cast;

  • аpseudo-destructor call;

  • модификация объекта ([expr.ass],[expr.post.incr], [expr.pre.incr]) , если оно не применяются к энергонезависимому именующему буквальному типу , который ссылается на энергонезависимый объект , чей срок служба начался в оценкеe;

  • atypeid expression , операнд которого является значением glvalue типа полиморфного класса;

  • а new-expression;

  • а delete-expression;

  • relational илиequality оператора , где результат не определен; или

  • а throw-expression.

Если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, где преобразованное выражение является выражением постоянная и неявное последовательность преобразования содержит только

и где привязка ссылки (если есть) привязывается напрямую. [ Note: Такие выражения могут использоватьсяnew expressions, какcase expressions, как инициализаторы перечислителя, если базовый тип fixed, какarray границы, так и не типtemplate arguments. ] A - это выражение, где преобразованное выражение является постоянным выражением, а последовательность преобразования содержит только указанные выше преобразования.end notecontextually 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 exampleend 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]

Тем не менее, реализациям рекомендуется обеспечивать согласованные результаты независимо от того, выполнялась ли оценка во время перевода и / или во время выполнения программы.