The constexpr specifier shall be applied only to the definition of a variable, 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 or function template has 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 int 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(square(a)), y(square(a)) // OK: definition { } constexpr pixel small(2); // error: square not defined, so small(2) // not constant ([expr.const]) so constexpr not satisfied constexpr int square(int x) { // OK: definition return 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:
it shall not be virtual ([class.virtual]);
its return type shall be a literal type;
each of its parameter types shall be a literal type;
its function-body shall be = delete, = default, or a compound-statement that contains only
null statements,
typedef declarations and alias-declarations that do not define classes or enumerations,
and exactly one return statement;
every constructor call and implicit conversion used in initializing the return value ([stmt.return], [dcl.init]) shall be one of those allowed in a constant expression ([expr.const]).
[ Example:
constexpr int square(int x) { return x * x; } // OK constexpr long long_max() { return 2147483647; } // OK constexpr int abs(int x) { return x < 0 ? -x : x; } // OK constexpr void f(int x) // error: return type is void /* ... */ constexpr int prev(int x) { return --x; } // error: use of decrement constexpr int g(int x, int n) { // error: body not just “return expr” int r = 1; while (--n > 0) r *= x; return r; }
— end example ]
In a definition of a constexpr constructor, each of the parameter types shall be a literal type. In addition, either its function-body shall be = delete or = default or it shall satisfy the following constraints:
the class shall not have any virtual base classes;
its function-body shall not be a function-try-block;
the compound-statement of its function-body shall contain only
null statements,
typedef declarations and alias-declarations that do not define classes or enumerations,
and using-directives;
every non-static data member and base class sub-object shall be initialized ([class.base.init]);
every constructor involved in initializing non-static data members and base class sub-objects shall be a constexpr constructor;
every assignment-expression that is an initializer-clause appearing directly or indirectly within a brace-or-equal-initializer for a non-static data member that is not named by a mem-initializer-id shall be a constant expression; and
every implicit conversion used in converting a constructor argument to the corresponding parameter type and converting a full-expression to the corresponding member type shall be one of those allowed in a constant expression.
[ Example:
struct Length { explicit constexpr Length(int i = 0) : val(i) { } private: int val; };
— end example ]
Function invocation substitution for a call of a constexpr function or of a constexpr constructor means implicitly converting each argument to the corresponding parameter type as if by copy-initialization,91 substituting that converted expression for each use of the corresponding parameter in the function-body, and, for constexpr functions, implicitly converting the resulting returned expression or braced-init-list to the return type of the function as if by copy-initialization. Such substitution does not change the meaning. [ Example:
constexpr int f(void *) { return 0; } constexpr int f(...) { return 1; } constexpr int g1() { return f(0); } // calls f(void *) constexpr int g2(int n) { return f(n); } // calls f(...) even for n == 0 constexpr int g3(int n) { return f(n*0); } // calls f(...) namespace N { constexpr int c = 5; constexpr int h() { return c; } } constexpr int c = 0; constexpr int g4() { return N::h(); } // value is 5, c is not looked up again after the substitution
— end example ]
For a constexpr function, if no function argument values exist such that the function invocation substitution would produce a constant expression ([expr.const]), the program is ill-formed; no diagnostic required. For a constexpr constructor, if no argument values exist such that after function invocation substitution, every constructor call and full-expression in the mem-initializers would be a constant expression (including conversions), the program is ill-formed; no diagnostic required. [ Example:
constexpr int f(bool b) { return b ? throw 0 : 0; } // OK constexpr int f() { throw 0; } // 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 not a constexpr function or constexpr constructor. [ Note: If the function is a member function it will still be const as described below. — end note ] If no specialization of the template would yield a constexpr function or constexpr constructor, the program 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.
A constexpr specifier for a non-static member function that is not a constructor declares that member function to be const ([class.mfct.non-static]). [ Note: The constexpr specifier has no other effect on the function type. — end note ] The keyword const is ignored if it appears in the cv-qualifier-seq of the function declarator of the declaration of such a member function. The class of which that function is a member shall be a literal type ([basic.types]). [ Example:
class debug_flag { public: explicit debug_flag(bool); constexpr bool is_on(); // error: debug_flag not // literal type private: bool flag; }; 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. Each implicit conversion used in converting the initializer expressions and each constructor call used for the initialization shall be one of those allowed in a constant expression ([expr.const]). [ Example:
struct pixel { int x, y; }; constexpr pixel ur = { 1294, 1024 };// OK constexpr pixel origin; // error: initializer missing
— end example ]
The resulting converted value will include an lvalue-to-rvalue conversion ([conv.lval]) if the corresponding copy-initialization requires one.