I got this example from §5.19/2 in N4140:
constexpr int incr(int &n) {
return ++n;
}
As far as I can tell, this is not a constexp
In C++14 the rules for constexpr function were relaxed and the paper N3597: Relaxing constraints on constexpr functions. The paper goes into the rationale and the effects and it includes the following (emphasis mine):
As in C++11, the constexpr keyword is used to mark functions which the implementation is required to evaluate during translation, if they are used from a context where a constant expression is required. Any valid C++ code is permitted in constexpr functions, including the creation and modification of local variables, and almost all statements, with the restriction that it must be possible for a constexpr function to be used from within a constant expression. A constant expression may still have side-effects which are local to the evaluation and its result.
and:
A handful of syntactic restrictions on constexpr functions are retained:
- asm-declarations are not permitted.
- try-blocks and function-try-blocks are not permitted.
- Declarations of variables with static and thread storage duration have some restrictions (see below).
and we can find this covered in N4140 section 7.1.5
[dcl.constexpr] which says:
The definition of a constexpr function shall satisfy the following constraints:
it shall not be virtual (10.3);
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 does not contain
an asm-definition,
a goto statement,
a try-block, or
a definition of a variable of non-literal type or of static or thread storage duration or for which no initialization is performed.
The last example shows how incr
can be used in a constexpr:
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)
and the rule that covers the lifetime of k begins inside h(1)
is:
- modification of an object (5.17, 5.2.6, 5.3.2) unless it is applied to a non-volatile lvalue of literal type that refers to a non-volatile object whose lifetime began within the evaluation of e;
The wording in 7.1.5
[dcl.constexpr] shows us why incr
is a valid constexpr:
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 (5.19), the program is ill-formed; no diagnostic required.
As the modified example given by T.C.:
constexpr int& as_lvalue(int&& i){ return i; }
constexpr int x = incr(as_lvalue(1)) ;
shows, we can indeed use incr
as a subexpression of a core constant expression and therefore it is not ill-formed.