7 Declarations [dcl.dcl]

7.1 Specifiers [dcl.spec]

7.1.5 The constexpr specifier [dcl.constexpr]

The constexpr specifier shall be applied only to the definition of a variable or variable template, the declaration of a function or function template, or the declaration of a static data member of a literal type ([basic.types]). If any declaration of a function, function template, or variable 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. constexpr functions and constexpr constructors are implicitly inline ([dcl.fct.spec]).

The definition of a constexpr function shall satisfy the following constraints:

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 constraints:

  • the class shall not have any virtual base classes;

  • each of the parameter types shall be a literal type;

  • its function-body shall not be a function-try-block;

In addition, either its function-body shall be = delete, or it shall satisfy the following constraints:

  • either its function-body shall be = default, or the compound-statement of its function-body shall satisfy the constraints for a function-body of a constexpr function;

  • every non-variant non-static data member and base class sub-object 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 sub-objects 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 non-template, non-defaulted constexpr function or a non-template, non-defaulted, non-inheriting constexpr constructor, if no argument values exist such that an invocation of the function or constructor could be an evaluated subexpression of a core constant expression ([expr.const]), 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 a call to a constexpr function can appear in a constant expression.

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. If it is initialized by a constructor call, that call shall be a constant expression ([expr.const]). Otherwise, or if a constexpr specifier is used in a reference declaration, every full-expression that appears in its initializer shall be a constant expression. [ Note: Each implicit conversion used in converting the initializer expressions and each constructor call used for the initialization is part of such a full-expression.  — end note ] [ Example:

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

 — end example ]