10 Declarations [dcl.dcl]

10.1 Specifiers [dcl.spec]

10.1.5 The constexpr specifier [dcl.constexpr]

Спецификатор constexpr должен применяться только к определению переменной или шаблона переменной или к объявлению функции или шаблона функции. Функция или статический член данных, объявленный с помощью constexpr спецификатора, неявно является встроенной функцией или переменной ([dcl.inline]). Если какое-либо объявление функции или шаблона функции имеет constexpr спецификатор, то все его объявления должны содержать constexpr спецификатор. [ Note: Явная специализация может отличаться от объявления шаблона в отношении constexpr спецификатора. ] [ Параметры функции не могут быть объявлены . ] [ end noteNote: constexprend noteExample:

constexpr void square(int &x);  // OK: declaration
constexpr int bufsz = 1024;     // OK: definition
constexpr struct pixel {        // error: pixel is a type
  int x;
  int y;
  constexpr pixel(int);         // OK: declaration
};
constexpr pixel::pixel(int a)
  : x(a), y(x)                  // OK: definition
  { square(x); }
constexpr pixel small(2);       // error: square not defined, so small(2)
                                // not constant ([expr.const]) so constexpr not satisfied

constexpr void square(int &x) { // OK: definition
  x *= x;
}
constexpr pixel large(4);       // OK: square defined
int next(constexpr int x) {     // error: not for parameters
     return x + 1;
}
extern constexpr int memsz;     // error: not a definition

end example]

constexpr Спецификатор используется в объявлении функции, не конструктор заявляет , что функция будет constexpr function. Точно так же constexpr спецификатор, используемый в объявлении конструктора, объявляет, что этот конструктор является constexpr constructor.

Определение функции constexpr должно удовлетворять следующим требованиям:

  • не должно быть virtual;

  • его возвращаемый тип должен быть буквальным;

  • каждый из его типов параметров должен быть буквальным типом;

  • это function-bodyдолжно быть = delete, = defaultили, compound-statement которое не содержит

    • ан asm-definition,

    • goto заявление,

    • ан identifier label,

    • а try-block, или

    • определение переменной нелитерального типа, либо статической, либо продолжительности хранения потока, либо для которой не выполняется инициализация.

[Example:

constexpr int square(int x)
  { return x * x; }             // OK
constexpr long long_max()
  { return 2147483647; }        // OK
constexpr int abs(int x) {
  if (x < 0)
    x = -x;
  return x;                     // OK
}
constexpr int first(int n) {
  static int value = n;         // error: variable has static storage duration
  return value;
}
constexpr int uninit() {
  int a;                        // error: variable is uninitialized
  return a;
}
constexpr int prev(int x)
  { return --x; }               // OK
constexpr int g(int x, int n) { // OK
  int r = 1;
  while (--n > 0) r *= x;
  return r;
}

end example]

Определение конструктора constexpr должно удовлетворять следующим требованиям:

  • у класса не должно быть никаких виртуальных базовых классов;

  • каждый из типов параметров должен быть буквальным типом;

  • его function-bodyне должно быть function-try-block.

Кроме того, он либо function-bodyдолжен быть = delete, либо удовлетворять следующим требованиям:

  • либо его function-bodyдолжно быть = default, либо compound-statementего function-body должно удовлетворять требованиям для function-bodyфункции constexpr;

  • каждый невариантный нестатический член данных и подобъект базового класса должен быть инициализирован ([class.base.init]);

  • если класс является объединением, имеющим вариантные члены ([class.union]), должен быть инициализирован ровно один из них;

  • если класс является подобным объединению классом, но не является объединением, для каждого из его анонимных членов объединения, имеющих вариантные члены, должен быть инициализирован ровно один из них;

  • для конструктора без делегирования каждый конструктор, выбранный для инициализации нестатических членов данных и подобъектов базового класса, должен быть конструктором constexpr;

  • для делегирующего конструктора целевой конструктор должен быть конструктором constexpr.

[Example:

struct Length {
  constexpr explicit Length(int i = 0) : val(i) { }
private:
  int val;
};

end example]

Для функции constexpr или конструктора constexpr, который не является ни заданным по умолчанию, ни шаблоном, если не существует таких значений аргументов, что вызов функции или конструктора мог быть вычисленным подвыражением a core constant expression, или, для конструктора, константным инициализатором для некоторого объекта ([basic.start.static]), программа некорректна, диагностика не требуется. [Example:

constexpr int f(bool b)
  { return b ? throw 0 : 0; }           // OK
constexpr int f() { return f(true); }   // ill-formed, no diagnostic required

struct B {
  constexpr B(int x) : i(0) { }         // x is unused
  int i;
};

int global;

struct D : B {
  constexpr D() : B(global) { }         // ill-formed, no diagnostic required
                                        // lvalue-to-rvalue conversion on non-constant global
};

end example]

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

Вызов функции constexpr дает тот же результат, что и вызов эквивалентной функции non-constexpr во всех отношениях, за исключением того, что

  • вызов функции constexpr может появиться в constant expression и

  • copy elision является обязательным в постоянном выражении ([class.copy]).

Спецификатор constexpr не влияет на тип функции constexpr или конструктора constexpr. [Example:

constexpr int bar(int x, int y)         // OK
    { return x + y + x*y; }
// ...
int bar(int x, int y)                   // error: redefinition of bar
    { return x * 2 + 3 * y; }

end example]

constexpr Спецификатор используется в объявлении объекта объявляет объект как const. Такой объект должен иметь буквальный тип и быть инициализирован. В любом constexpr объявлении переменной полное выражение инициализации должно быть constant expression. [Example:

struct pixel {
  int x, y;
};
constexpr pixel ur = { 1294, 1024 };    // OK
constexpr pixel origin;                 // error: initializer missing

end example]