C ++中的lambda类型

时间:2014-11-05 02:25:19

标签: c++ lambda

我正在尝试用C ++学习lambdas,但偶然发现了一些我无法理解的内容。

这是代码:

#include <iostream>

typedef double Func(double); 

double applyFunc(Func f, double x)
{
    return f(x);
}

int main()
{
    std::cout << applyFunc([](double x) {return x + 1;}, 3) << std::endl;
}

现在这很好用(打印“4”),即使用的lambda表达式的类型正好是double (*)(double)

但是如果我在lambda表达式中添加闭包,比如:

int main()
{
    int n = 5;
    std::cout << applyFunc([n](double x) {return x + n;}, 3) << std::endl;
}

然后我从编译器得到错误:

In function ‘int main()’:
error: cannot convert ‘main()::__lambda0’ to ‘double (*)(double)’ for argument ‘1’ to ‘double applyFunc(double (*)(double), double)’
  3) << std::endl;
   ^

我不明白为什么会这样。我的意思是,从applyFunc()的角度来看,它仍然收到一个指向函数的指针,该函数采用double参数并返回double,并且它不知道我们使用变量'n'从上下文来看,所以lambda表达式的类型应该是相同的,就像在第一个例子中一样,对吗?

我非常感谢您的帮助,谢谢您!

2 个答案:

答案 0 :(得分:4)

只有在没有捕获的情况下,lambda才可转换为函数指针,我们可以通过转到草案标准部分5.1.2 Lambda表达式来看到这一点(强调我的):

  

没有lambda-capture 的lambda表达式的闭包类型有一个   公共非虚拟非显式const 转换函数到指针   使用具有与闭包相同的参数和返回类型   type的函数调用运算符。此转换返回的值   function应该是一个函数的地址,当被调用时,它具有   与调用闭包类型的函数调用操作符的效果相同。

这是一种不依赖于此转换的替代解决方案:

template <typename Callable>
double applyFunc(Callable f, double x)
{
    return f(x);
}

更新

如果您对使用std::function和模板之间的区别感兴趣,那么您应该阅读std::function vs template。那里有很多好的答案,还有很多值得思考的东西。

答案 1 :(得分:2)

每个lambda表达式返回一个具有不同类型的对象。如果lambda表达式捕获任何变量,则可以将其转换为适当签名的函数指针类型(即,返回类型和参数需要与lambda表达式的那些一致)。当捕获变量时,创建的实体不能由普通函数表示。相反,lambda表达式产生一个带有函数调用操作符的类类型的对象。也就是说,你的第二个代码使用一个lambda表达式,产生一个类的对象,大致相当于这个:

class lambda {
     int n;
public:
     lambda(int n): n(n) {}
     double operator()(double x) const { return x + n; }
};