Relevant part of the C++17 standard [class.copy.elision/3]:
In the following copy-initialization contexts, a move operation might be used instead of a copy operation:
- If the expression in a
return
statement is a (possibly parenthesized) id-expression that names an object with automatic storage duration declared in the body or parameter-declaration-clause of the innermost enclosing function...
This does not hold for:
Widget makeWidget(Widget&& w)
{
return w;
}
since w
does not name an object with automatic storage duration (within the function).
In C++20, the situation is different:
An implicitly movable entity is a variable of automatic storage duration that is either a non-volatile object or an rvalue reference to a non-volatile object type. In the following copy-initialization contexts, a move operation might be used instead of a copy operation:
- If the expression in a
return
or co_return
statement is a (possibly parenthesized) id-expression that names an implicitly movable entity declared in the body or parameter-declaration-clause of the innermost enclosing function...
Here, the reference w
satisfies those requirements since it is an rvalue reference declared in the parameter-declaration-clause.
Why the same was not until C++20? I cannot say; likely nobody proposed such a change before.