简体   繁体   English

C ++中的lambda类型

[英]Type of lambdas in C++

I am trying to learn lambdas in C++, but stumbled on something I can't quite understand. 我试图学习C ++中的lambda,但是偶然发现了一些我不太了解的东西。

Here is code: 这是代码:

#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;
}

Now this works just fine (prints "4"), ie type of the lambda expression used is exactly double (*)(double) . 现在这可以正常工作(打印“ 4”),即所使用的lambda表达式的类型恰好是double (*)(double)

But if I add closure to the lambda expression, like: 但是,如果我在lambda表达式中添加闭包,例如:

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

Then I get an error from the compiler: 然后我从编译器得到一个错误:

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

And I don't understand why is that. 我不明白为什么会这样。 I mean, from the point of view of applyFunc() it still receives a pointer to a function taking double argument and returning double , and it doesn't know that we used variable 'n' from context, so the type of lambda expression should be the same, as in the first example, right? 我的意思是,从applyFunc()的角度来看,它仍然接收指向带有double参数并返回double的函数的指针,并且它不知道我们从上下文中使用了变量'n',因此lambda表达式的类型应该与第一个示例相同,对吗?

I would very appreciate help, thank you in advance! 非常感谢您的帮助,在此先感谢您!

A lambda is convertable to a function pointer only if it does not have a capture, we can see this by going to the draft standard section 5.1.2 Lambda expressions which says ( emphasis mine ): Lambda只有在没有捕获的情况下才可以转换为函数指针,我们可以通过转至标准草案第5.1.2Lambda表达式来说明这一点,该表达式表示( 强调我的 ):

The closure type for a lambda-expression with no lambda-capture has a public non-virtual non-explicit const conversion function to pointer to function having the same parameter and return types as the closure type's function call operator. 没有lambda捕获的lambda表达式的闭包类型具有指向该函数的指针的公共非虚拟非显式const 转换函数,该函数具有与闭包类型的函数调用运算符相同的参数和返回类型。 The value returned by this conversion function shall be the address of a function that, when invoked, has the same effect as invoking the closure type's function call operator. 该转换函数返回的值应是一个函数的地址,该函数在被调用时与调用闭包类型的函数调用操作符具有相同的作用。

This is an alternative solution which does not rely on this conversion: 这是不依赖此转换的替代解决方案:

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

Update 更新

If you are interested in the difference between using std::function and templates then you should read std::function vs template . 如果您对使用std::function和template之间的差异感兴趣,则应阅读std :: function vs template There are many good answers there and a lot of food for thought. 那里有很多好的答案,还有很多值得深思的地方。

Each lambda expression returns an object with a distinct type. 每个lambda表达式返回一个具有不同类型的对象。 If the lambda expression does not capture any variables, it can be converted to aa function pointer type of an appropriate signature (ie, the return type and the arguments need to agree with those of the lambda expression). 如果lambda表达式没有捕获任何变量,则可以将其转换为具有适当签名的函数指针类型(即,返回类型和参数必须与lambda表达式的那些一致)。 When there is a variable captured, the entity created can't be represented by a plain function. 当捕获了一个变量时,创建的实体不能用普通函数表示。 Instead, the lambda expression yields an object of class type with a function call operator. 相反,lambda表达式使用函数调用运算符产生类类型的对象。 That is, your second code uses a lambda expression yielding an object of a class which is roughly equivalent to this: 也就是说,您的第二个代码使用了一个lambda表达式,该表达式产生的类的对象大致与此相同:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM