The move constructor A::A(A&&)
should be used here due to the implicit move rule for local variable and parameters when returning by value:
If expression is a (possibly parenthesized) id-expression that names a variable whose type is either
and that variable is declared
then overload resolution to select the constructor to use for initialization of the returned value or, for co_return, to select the overload of promise.return_value() (since C++20) is performed twice:
- first as if expression were an rvalue expression (thus it may select the move constructor), and
- if the first overload resolution failed or
- it succeeded, but did not select the move constructor (formally, the first parameter of the selected constructor was not an rvalue reference to the (possibly cv-qualified) type of expression) (until C++20)
- then overload resolution is performed as usual, with expression considered as an lvalue (so it may select the copy constructor).
(emphasis mine)
In your example, you have the statement return a;
and a
is a parameter of the innermost enclosing function, thus overload resolution can be performed twice. In the first step a
is treated as if it were an rvalue expression and so the move constructor can be used here.
Note there is no need to perform the second step as the first step succeeded.