If I understood correctly, starting from C++17, this code now requires that no copy will be done:
Foo myfunc(void) {
return Foo();
}
auto foo = myfunc(); // no copy
Is it also true for function arguments? Will copies be optimized away in the following code?
Foo myfunc(Foo foo) {
return foo;
}
auto foo = myfunc(Foo()); // will there be copies?
In C++17, prvalues ("anonymous temporaries") are no longer objects. Instead, they are instructions on how to construct an object.
They can instantiate a temporary from their construction instructions, but as there is no object there, there is no copy/move construction to elide.
Foo myfunc(Foo foo) {
return foo;
}
So here, the function argument foo
is moved into the prvalue return value of myfunc
. You can think of this conceptually as "myfunc
returns instructions on how to make a Foo
". If those instructions are "not used" by your program, a temporary is automatically instantiated and uses those instructions.
(The instructions, by the way, include time travel provisions; the time-point of construction remains inside the function itself!)
auto foo = myfunc(Foo());
So here, Foo()
is a prvalue. It says "construct a Foo
using the ()
constructor". It is then used to construct the argument of myfunc
. No elision occurs, no copy constructor or move constructor is called, just ()
.
Stuff then happens inside myfunc
.
myfunc
returns a prvalue of type Foo
. This prvalue (aka construction instructions) is used to construct the local variable auto foo
.
So what happens here is that a Foo
is constructed via ()
, then moved into auto foo
.
Elision of function arguments into return values is not supported in C++14 nor C++17 as far as I know (I could be wrong, I do not have chapter and verse of the standard here). However, they are implicitly moved when used in a return func_arg;
context.