I am trying to learn lambdas in C++, but stumbled on something I can't quite understand.
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"), i.e. type of the lambda expression used is exactly double (*)(double)
.
But if I add closure to the lambda expression, like:
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?
I would very appreciate help, thank you in advance!
Each lambda expression returns an object with a distinct type. If the lambda expression does not capture any variables, it can be converted to a a function pointer type of an appropriate signature (i.e., the return type and the arguments need to agree with those of the lambda expression). 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. That is, your second code uses a lambda expression yielding an object of a class which is roughly equivalent to this:
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):This is an alternative solution which does not rely on this conversion:
Update
If you are interested in the difference between using
std::function
and templates then you should read std::function vs template. There are many good answers there and a lot of food for thought.