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


18

我发现lvaluelambda闭包始终可以作为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为了演示目的而使用a ,但是任何其他类型的行为都相同)。

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


5
我猜这是因为fn1被隐式转换为std::functionin foo(fn1)。那个临时函数就是一个右值。
eike

@RichardCritten我确实不确定,所以我没有发布答案。我认为现在不再需要另一个。
eike

1
@eike np我经常有同样的感觉,是的,答案很多。
理查德·克里滕

2
@Sumudu提出问题的人误导了您,因为他们不知道他们想问什么。他们要问的是:“为什么不能std::function从lambda推论模板参数”。您的程序不会尝试推导的模板参数std::function,因此隐式转换没有问题。
eerorika

1
您链接的问题的标题有点误导。std::function有一个接受lambda闭包的非显式构造函数,因此存在隐式转换。但是在链接问题的情况下,std::function无法从lambda类型推断出的模板实例化。(例如std::function<void()>[](){return 5;}即使具有非空返回类型也可以从构造
。– eike

Answers:


8

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

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

首先,std::function<void()>从构造一个临时对象[]{}。使用的构造是#5 在这里,它会将封盖进入std::function实例:

template< class F >
function( F f );

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

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


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

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


8

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

情况1起作用是因为lambda可转换为std::functions。这意味着可以std::function通过复制 来实现临时文件fn1。该临时变量可以绑定到右值引用,因此参数与参数匹配。

而且复制也是为什么fn1完全不受发生的任何影响的原因foo


5

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

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

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

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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.