C++中Lambda的类型

Type of lambdas in C++

本文关键字:类型 Lambda C++      更新时间:2023-10-16

我试图用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表达式的类型应该与第一个示例中的相同,对吧?

我将非常感谢您的帮助,提前感谢您!

lambda只有在没有捕获的情况下才能转换为函数指针,我们可以通过标准草案5.1.2lambda表达式来了解这一点,其中说(emphasis mine):

没有lambda捕获的lambda表达式的闭包类型具有public非虚拟非显式const到指针的转换函数函数具有与闭包相同的参数和返回类型类型的函数调用运算符。此转换返回的值函数应为调用时具有与调用闭包类型的函数调用操作符的效果相同。

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

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

更新

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

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

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