【问题标题】:C++11 lambda can be assigned to std::function with incorrect signature可以将 C++11 lambda 分配给签名不正确的 std::function
【发布时间】:2015-05-13 23:54:12
【问题描述】:

以下编译并运行(在 Apple LLVM 版本 6.1.0 和 Visual C++ 2015 下):

#include <functional>
#include <iostream>

struct s { int x; };

int main(int argc, char **argv)
{
    std::function<void (s &&)> f = [](const s &p) { std::cout << p.x; };
    f(s {1});
    return 0;
}

为什么赋值std::function&lt;void (s &amp;&amp;)&gt; f = [](const s &amp;p) { std::cout &lt;&lt; p.x; }; 不会产生错误?接受右值引用的函数不应该与接受 const 左值引用的函数具有相同的签名,不是吗?从 lambda 的声明中删除 const 确实会产生预期的错误。

【问题讨论】:

  • gcc 5.1 也不抱怨。
  • 吹毛求疵:你没有分配给std::function。尽管语法非常相似,std::function&lt;..&gt; f = ..; 是一个初始化而不是赋值,因为它定义了一个新对象。
  • 这类似于函数参数的普通逆变。

标签: c++ c++11 lambda rvalue-reference


【解决方案1】:

扩展现有评论和答案:

std::function&lt;R(A...)&gt; 的意义在于它可以包装任何可以用A... 调用的函数或函子,并将结果存储在R 中。

例如,

std::function<int(int)> f = [](long l) { return l; };

只是桃子。

所以当你看到这样的事情时你必须问自己:如果你有一个 lambda 取 const T &amp;,并且你有一个 T &amp;&amp; 类型的表达式(或者,更准确地说,你有一个 @ 类型的 xvalue 987654328@),你能用那个表达式来调用lambda吗?

是的,你可以。

如果可以,那么std::function 应该能够存储该函子。这几乎是std::function 的重点。

【讨论】:

  • 这也适用于类层次结构,std::function&lt;void(Derived*)&gt; f = [](Base *){ };
  • 不错的答案,+1,这是我第一次听到这个。它在幕后是如何运作的?类型擦除?
  • @vsoftco 是的,详情请参阅R. Martinho Fernandes's excellent answer here
  • @vsoft 例如,有一些对象具有 std 函数所具有的描述签名,并在其中调用 lambda。
  • @hvd,感谢您的链接,正是我想知道的。
【解决方案2】:

请对此持保留态度。这是我理解的,但我不确定。

考虑以下输出:

int main(int argc, char **argv)
{
  std::cout <<  std::is_convertible<s &&, s&>::value << std::endl;       //false                                                      
  std::cout <<  std::is_convertible<s &&, const s&>::value << std::endl; //true                                                     

  std::cout <<  std::is_convertible<const s &, s&&>::value << std::endl; //false                                                     
  return 0;
}

这表明可以将s &amp;&amp; 转换为const s&amp;。这就是std::function 的分配没问题的原因。

从 lambda 的声明中删除 const 确实会生成一个 如预期的错误。

确实这是因为(如前所示)将s &amp;&amp; 转换为s &amp; 是不可能的。

以同样的方式,尝试相反的方式:

std::function&lt;void (const s &amp;)&gt; f = [](s &amp;&amp;p) { std::cout &lt;&lt; p.x; }; 会失败,因为无法转换 const s&amp;s &amp;&amp;

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-03-11
    • 2015-05-23
    • 2016-12-14
    • 1970-01-01
    • 1970-01-01
    • 2016-12-18
    • 2021-12-27
    相关资源
    最近更新 更多