Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Lambda closure lvalues can be passed as rvalue reference parameters

I found that lvalue lambda closures can always be passed as rvalue function parameters.

See the following simple demonstration.

#include <iostream>
#include <functional>

using namespace std;

void foo(std::function<void()>&& t)
{
}

int main()
{
    // Case 1: passing a `lvalue` closure
    auto fn1 = []{};
    foo(fn1);                          // works

    // Case 2: passing a `lvalue` function object
    std::function<void()> fn2 = []{};
    foo(fn2);                          // compile error

    return 0;
}

Case 2 is the standard behavior (I just used a std::function for demonstration purposes, but any other type would behave the same).

How and why does case 1 work ? What is the state of fn1 closure after the function returned ?

like image 241
Anubis Avatar asked Nov 12 '19 12:11

Anubis


Video Answer


1 Answers

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). If f 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.

like image 136
Vittorio Romeo Avatar answered Oct 24 '22 20:10

Vittorio Romeo