【问题标题】:Lambda closure lvalues can be passed as rvalue reference parametersLambda 闭包左值可以作为右值引用参数传递
【发布时间】:2020-03-08 03:55:06
【问题描述】:

我发现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闭包是什么状态?

【问题讨论】:

  • 我猜这是因为fn1foo(fn1) 中被隐式转换为std::function。那么这个临时函数就是一个右值。
  • @RichardCritten 我真的不确定,所以我没有发布答案。我认为现在不需要另一个了。
  • @eike np 我经常有同样的感觉,是的,很多答案。
  • @Sumudu 问这个问题的人误导了你,因为他们不知道他们想问什么。他们的意思是:“为什么不能从 lambda 推导出 std::function 的模板参数”。你的程序没有尝试推导出std::function的模板参数,所以隐式转换没有问题。
  • 您链接的问题的标题有点误导。 std::function 有一个接受 lambda 闭包的非显式构造函数,因此存在隐式转换。但是在链接问题的情况下,无法从 lambda 类型推断出std::function 的模板实例化。 (例如,std::function&lt;void()&gt; 可以从 [](){return 5;} 构造,即使它具有非 void 返回类型。

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


【解决方案1】:

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

调用foo 需要绑定到右值引用std::function&lt;void()&gt; 实例。 std::function&lt;void()&gt; 可以从任何与void() 签名兼容的可调用对象 构造。

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

template< class F >
function( F f );

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

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


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

和以前一样,因为它被复制到了std::function 实例中。原来的关闭不受影响。

【讨论】:

    【解决方案2】:

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

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

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

    【讨论】:

      【解决方案3】:

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

      fn1 是无状态的,因为它什么都不捕获。

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

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-01-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-09-09
        • 1970-01-01
        相关资源
        最近更新 更多