Lambda闭包左值可以作为右值参考参数传递

时间:2019-11-12 12:23:06

标签: c++ lambda closures c++14 rvalue-reference

我发现lvalue lambda闭包始终可以作为rvalue函数参数来传递。

请参见以下简单演示。

#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;
}

案例2是标准行为(出于演示目的,我仅使用std::function,但是其他类型的行为都相同)。

案例1如何以及为什么起作用?函数返回后fn1关闭的状态是什么?

3 个答案:

答案 0 :(得分:8)

lambda不是std::function。引用不会直接绑定

案例1之所以有效,是因为lambda可转换为std::function。这意味着通过复制 std::function实现了临时fn1。该临时变量可以绑定到右值引用,因此参数与参数匹配。

复制也是fn1完全不受foo中发生的任何事情影响的原因。

答案 1 :(得分:8)

  

案例1如何以及为什么起作用?

调用foo需要一个std::function<void()>实例,该实例绑定到右值引用std::function<void()>可以由任何与void()签名兼容的 callable对象构造。

首先,从std::function<void()>构造一个临时[]{}对象。所使用的构造函数是#5 here,它将闭包复制到std::function实例中:

template< class F >
function( F f );
     

使用std::move(f)初始化目标。如果f是函数的空指针或成员的空指针,则*this在调用后将为空。

然后,临时function实例绑定到右值引用。


  

函数返回后fn1关闭的状态是什么?

与以前相同,因为它已被复制到std::function实例中。原始的封盖不受影响。

答案 2 :(得分:5)

  

函数返回后fn1关闭的状态是什么?

fn1是无状态的,因为它什么也没捕获。

  

案例1如何以及为什么起作用?

之所以起作用,是因为该参数的类型与所引用的右值的类型不同。由于类型不同,因此将考虑隐式转换。由于lambda对于此std::function的参数是可调用的,因此可以通过std::function的模板转换构造函数将其隐式转换为lambda。转换的结果是prvalue,因此可以与rvalue引用绑定。