10 Declarations [dcl.dcl]

10.1 Specifiers [dcl.spec]

10.1.5 The constexpr specifier [dcl.constexpr]

The constexpr specifier shall be applied only to the definition of a variable or variable template or the declaration of a function or function template.
A function or static data member declared with the constexpr specifier is implicitly an inline function or variable ([dcl.inline]).
If any declaration of a function or function template has a constexpr specifier, then all its declarations shall contain the constexpr specifier.
[Note
:
An explicit specialization can differ from the template declaration with respect to the constexpr specifier.
end note
]
[Note
:
Function parameters cannot be declared constexpr.
end note
]
[Example
:
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
]
A constexpr specifier used in the declaration of a function that is not a constructor declares that function to be a constexpr function.
Similarly, a constexpr specifier used in a constructor declaration declares that constructor to be a constexpr constructor.
The definition of a constexpr function shall satisfy the following requirements:
[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
]
The definition of a constexpr constructor shall satisfy the following requirements:
In addition, either its function-body shall be = delete, or it shall satisfy the following requirements:
  • either its function-body shall be = default, or the compound-statement of its function-body shall satisfy the requirements for a function-body of a constexpr function;
  • every non-variant non-static data member and base class subobject shall be initialized ([class.base.init]);
  • if the class is a union having variant members ([class.union]), exactly one of them shall be initialized;
  • if the class is a union-like class, but is not a union, for each of its anonymous union members having variant members, exactly one of them shall be initialized;
  • for a non-delegating constructor, every constructor selected to initialize non-static data members and base class subobjects shall be a constexpr constructor;
  • for a delegating constructor, the target constructor shall be a constexpr constructor.
[Example
:
struct Length {
  constexpr explicit Length(int i = 0) : val(i) { }
private:
  int val;
};
end example
]
For a constexpr function or constexpr constructor that is neither defaulted nor a template, if no argument values exist such that an invocation of the function or constructor could be an evaluated subexpression of a core constant expression, or, for a constructor, a constant initializer for some object ([basic.start.static]), the program is ill-formed, no diagnostic required.
[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
]
If the instantiated template specialization of a constexpr function template or member function of a class template would fail to satisfy the requirements for a constexpr function or constexpr constructor, that specialization is still a constexpr function or constexpr constructor, even though a call to such a function cannot appear in a constant expression.
If no specialization of the template would satisfy the requirements for a constexpr function or constexpr constructor when considered as a non-template function or constructor, the template is ill-formed, no diagnostic required.
A call to a constexpr function produces the same result as a call to an equivalent non-constexpr function in all respects except that
The constexpr specifier has no effect on the type of a constexpr function or a constexpr constructor.
[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
]
A constexpr specifier used in an object declaration declares the object as const.
Such an object shall have literal type and shall be initialized.
In any constexpr variable declaration, the full-expression of the initialization shall be a constant expression.
[Example
:
struct pixel {
  int x, y;
};
constexpr pixel ur = { 1294, 1024 };    // OK
constexpr pixel origin;                 // error: initializer missing
end example
]