【问题标题】:Auto type deduction and passing a lambda to an std::function parameter自动类型推导并将 lambda 传递给 std::function 参数
【发布时间】:2017-01-20 12:45:27
【问题描述】:

假设我有一个具有以下签名的函数:

void foo(std::function<void(int&)>& bar);

以下调用编译成功:

foo([](int& x) { ++x; });

这也编译成功了:

std::function<void(int&)> myFunction = [](int& x) { ++x; };
foo(myFunction);

但是使用自动类型推断,它突然无法编译:

auto myFunction = [](int& x) { ++x; };
foo(myFunction);

AFAIK 推断的 lambda 类型未指定,但它应该充当仿函数/可调用对象。我不明白的是,如果不允许将相同的 lambda 作为同一类型的函数参数传递,怎么可能将相同的 lambda 分配给 std::function&lt;void(int&amp;)&gt;

在 GCC v4.8.5 上测试,使用 -std=c++11

【问题讨论】:

  • 缺少const 的情况下都可以正常编译(Demo)。但没有第二个 sn-p 作品(如我所料)Demo
  • 你的第一个例子编译???它不是herehere
  • 是的,在其他答案提到该代码不应该编译之后,我检查了 cpp.sh 和 godbolt(在那里使用 gcc v4.8.5),它确实没有编译。很奇怪,因为在我的工作机器上 gcc 编译它没有问题,现在我得到了解释你如何只能将右值绑定到常量引用的答案......

标签: c++ c++11 lambda


【解决方案1】:

鉴于这种情况;

std::function<void(int&)> myFunction = [](int& x) { ++x; };
foo(myFunction);

发生转换,结果存储在命名对象myFunction 中。反过来,命名对象可以绑定到foo 所需的引用。

鉴于其他两种情况;

foo([](int& x) { ++x; });
// and
auto myFunction = [](int& x) { ++x; };
foo(myFunction);

可能发生从命名对象myFunction(在第二种情况下)到std::function的转换(在两种情况下);但产生了暂时的。临时无法绑定到foo 所需的std::function 引用,因此出现错误。如下添加const可以让代码编译;

void foo(std::function<void(int&)> const& bar);

允许临时对象绑定到const 引用。

Sample code.

【讨论】:

    【解决方案2】:

    以下调用编译成功:

    foo([](int& x) { ++x; });
    

    错了,是does not compile。原因是您不能将临时对象绑定到引用。

    出于同样的原因:

    auto myFunction = [](int& x) { ++x; };
    foo(myFunction);
    

    也不编译。 myFunction 的类型是 lambda 类型,因此创建了临时的,并将其传递给 foo,因为 foo 需要 std::function&lt;void(int&amp;)&gt;&amp;myFunction 必须隐式转换为 std::function&lt;void(int&amp;)&gt;

    这里:

    std::function<void(int&)> myFunction = [](int& x) { ++x; };
    foo(myFunction);
    

    没有临时创建。所以代码编译成功。

    【讨论】:

      【解决方案3】:

      引用与值不同。

      std::function<void(int&)>&
      

      这是一个参考。

      std::function<void(int&)>
      

      这是一个值。

      int&
      

      这是一个参考。

      int
      

      这是一个值。

      int x = 3.0;
      

      以上工作。

      int& x = 3.0;
      

      以上都行不通。

      std::function<void(int&)> f = [](int&x){++x;};
      

      以上工作。

      std::function<void(int&)>& f = [](int&x){++x;};
      

      以上都行不通。

      void foo(std::function<void(int&)>& bar);
      

      foo 引用std::function。这意味着它需要传递一个实际的std::function,而不是可以转换为它的东西。

      void foo2(std::function<void(int&)> const& bar);
      

      foo2const&amp; 转换为std::function。在这里,您可以将一些可转换的东西传递给std::function

      void foo3(std::function<void(int&)> bar);
      

      foo3 按值获取std::function。在这里,您可以将可转换的东西传递给std::function

      lambda 不是 std::function,但只要签名兼容,它就可以转换为 1。因此,这类似于“将double 传递给int”的情况,其中double 转换为int,但您无法将int&amp; 转换为double

      C++ 允许const&amp; 用于临时对象,但不允许&amp;,因为&amp; 暗示您打算更改它,并且更改不会通过临时对象传播。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2017-06-06
        • 1970-01-01
        • 1970-01-01
        • 2021-12-27
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多