可以使用不正确的签名将C++ 11 lambda分配给std :: function

Eag*_*gle 18 c++ lambda rvalue-reference c++11

以下编译和运行(在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;
}
Run Code Online (Sandbox Code Playgroud)

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

小智 23

扩展现有评论并回答:

关键std::function<R(A...)>是它可以包装任何可以调用的函数或函子,A...并将结果存储在一个函数中R.

所以,例如,

std::function<int(int)> f = [](long l) { return l; };
Run Code Online (Sandbox Code Playgroud)

只是桃子.

所以当你看到这样的东西时你必须问自己:如果你有一个lambda const T &,你有一个类型的表达式T &&(或者更确切地说,你有一个类型的xvalue T),你可以使用该表达式调用拉姆达?

是的你可以.

如果可以,那么std::function应该能够存储该仿函数.这几乎是主要观点std::function.


Xaq*_*aqq 8

请带上一粒盐.这是我的理解,但我不确定.

考虑以下输出:

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;
}
Run Code Online (Sandbox Code Playgroud)

这表明可以将a转换s &&为a const s&.这就是为什么这个std::function任务没问题.

从lambda声明中删除const会产生预期的错误.

实际上这是因为(如前所示),将a转换s &&为a s &是不可能的.

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

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