Lambda closure lvalues can be passed as rvalue reference parameters
How and why does case 1 work ?
Invoking foo
requires an instance of std::function<void()>
that binds to an rvalue reference. std::function<void()>
can be constructed from any callable object that is compatible with the void()
signature.
Firstly, a temporary std::function<void()>
object is constructed from []{}
. The constructor used is #5 here, which copies the closure into the std::function
instance:
template< class F > function( F f );
Initializes the target with
std::move(f)
. Iff
is a null pointer to function or null pointer to member,*this
will be empty after the call.
Then, the temporary function
instance is bound to the rvalue reference.
What is the state of fn1 closure after the function returned ?
Same as before, because it was copied into a std::function
instance. The original closure is unaffected.
A lambda is not a std::function
. The reference doesn't bind directly.
Case 1 works because lambdas are convertible to std::function
s. This means that a temporary std::function
is materialized by copying fn1
. Said temporary is able to be bound to an rvalue reference, and so the argument matches the parameter.
And the copying is also why fn1
is entirely unaffected by anything that happens in foo
.