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.
void
if the function takes no parameters? – Exploitervoid
? must have been long before my time with c++ – Cyprinoidvoid
- in C I remember there was a difference between empty and void (iirc empty allows any number of parameters?), and I guess I grown accustomed to it :) – Liverwurstfoo(void)
is only needed in C because in Cfoo()
means a function taking in any parameters. In C++foo()
means a function with no parameters,foo(void)
is only supported for backward compatibility. – Embattled