According to cppreference
In constant expression and constant initialization, copy elision is never performed.
Still it looks that it is not always so on practice. In the following program, function f
returns an object res
of type A
and it also takes on input a pointer p
on an object of same type, and they can be equal &res == p
AFAIK only in case of named return value optimization (NRVO) A res = f( &res )
:
struct A {
bool nrvo = false;
};
constexpr A f( A * p = nullptr ) {
A res = p ? A{ .nrvo = &res == p } : f( &res );
return res;
}
// fails in MSVC
static_assert( !f().nrvo );
So I would expect that .nrvo=false
during constant evaluation, but it is not the case at least in Visual Studio compiler. Online demo: https://gcc.godbolt.org/z/xfKccM1sv
Is the compiler incorrect here or some copy elisions may be done during constant evaluations?
Yes, according to the current rules NRVO is never performed in a context that requires a constant expression or during constant initialization. The static_assert
must succeed.
This was decided by CWG 2278 in 2019. Before this defect report, the rule was the other way around: NRVO was supposed to be always applied in such contexts, which turned out to be unimplementable.
The above applies to all forms of copy elision, not only NRVO.
However, "copy elisions" that were made mandatory with C++17, such as RVO from the prvalue result of a function call to initialize an object, are not copy elisions anymore. These behaviors became implemented as part of the object initialization rules instead and so also apply during constant expression evaluation.
The list of all permitted copy elisions can be found in [class.copy.elision], as can be the normative wording for cppreference's claim:
Copy elision is not permitted where an expression is evaluated in a context requiring a constant expression ([expr.const]) and in constant initialization ([basic.start.static]).