I have a function that takes function pointer as a parameter. Sometimes I would like to pass lamba instead of function pointer. However, my lambda captures so it can't be converted to function pointer.
So I was looking for solution, and I saw suggestion that I could store my lambda in std::function (I know that std::function is slow and I am fine with it).
So I've tried to do that, but I am getting compilation error. Here is my example:
That I don't want to do. Is there any other way? I don't need to use std::function.
I just want to construct something locally and pass it to DoSomething as a function pointer.
Well, you cannot convert a std::function to a function pointer for obvious reasons.
If DoSomething doesn't store the callback and you are only worried about the extra overhead of using std::function you might want to consider turning DoSomething into a function template where the type of the callback is deduced from the argument. This is how many of the standard algorithms work.
I got notification about your response in which you said:
Well, in that case I think you are out of luck. I guess you could use the C approach and pass a function pointer + a void* to the data that the function is responsible to interpret and use correctly. This is neither type-safe nor fun to work with so I wouldn't recommend going down that road, but it's the only way that I know to satisfy your requirement of using function pointers and no templates.
I got notification about your response in which you said:
[...]
but it haven't shown up here. Strange...
I decided to remove that post because I realized it probably wasn't helpful.
DoSomething(*ptr); // This is what I've added and it works!
Note that DoSomething is only called for f and g. If the std::function does not hold a function pointer (or something that can be converted to a function pointer) there is no way you can extract a function pointer from it.
It's because std::function can be implicitly constructed from a function pointer, so if your function takes a std::function as argument (as showed in my first reply) you can pass a function pointer, a lambda closure, or a std::function object, without having to do any explicit conversions.
Not sure why the cppreference example is so verbose. The main function could be simplified as follows.
1 2 3 4 5 6 7
int main()
{
test(std::plus<int>());
test(std::minus<int>());
test(f);
test(g);
}
Note that DoSomething is only called for f and g. If the std::function does not hold a function pointer (or something that can be converted to a function pointer) there is no way you can extract a function pointer from it.
Yes, but that is actually cool feature and sorf of type safety you've mentioned earlier.
if your function takes a std::function as argument (as showed in my first reply) you can pass a function pointer, a lambda closure, or a std::function object, without having to do any explicit conversions.
Ah, now I get it. I thought that I have to construct std::function if my method expects parameter of type std::function. Of coure, you have shown example with lambda but I just did not read it properly.
Does method with std::function parameter performs slower than method with function pointer? Even when I am not passing std::function to it? I guess it has to be slower because function pointer is implicitly converted to std::function.
Does method with std::function parameter performs slower than method with function pointer? Even when I am not passing std::function to it? I guess it has to be slower because function pointer is implicitly converted to std::function.
Yes, that is likely the case. How much of a difference it makes depends though. If it's a large function that is only called rarely it wouldn't matter. If it's a small function that is called a lot (e.g. a comparator for std::sort) then it might make the code significantly slower (perhaps 2-3x).
int c = 7;
auto my_lambda = [&](int a, int b)->int {return a + b + c; };
staticauto static_lambda = my_lambda;
int(*ptr)(int, int) = [](int a, int b) { return static_lambda(a, b); };
test(std::function<int(int, int)>(ptr));
So the idea is to wrap capturing lambda in capturless one :)
I've learned a lot, thank you.
If you are using std::function you shouldn't have to care about this stuff. I didn't even know about the target function before you showed me.
It is true that each lambda has its own type. If the lambda doesn't capture anything it can be implicitly converted to a function pointer, but that doesn't happen when you pass it to the std::function constructor because it accepts the lambda type just fine so no implicit conversion is necessary.
If you absolutely must store a function pointer inside the std::function object you could use an explicit cast ...
test(static_cast<int(*)(int, int)>([](int a, int b)->int {return a + b; }));
... but as I said, I don't think this should be necessary.
So the idea is to wrap capturing lambda in capturless one :)
You cannot do that.
A function pointer is just a pointer to some piece of code.
You can think of a lambda as creating an object that contains a function pointer plus everything that has been captured. A lambda that does not capture anything can be implicitly converted to a function pointer. This should be fine because the code that the function pointer refers to (i.e. the lambda body) does not use anything within the object (because it's empty).
If you were able to convert a capturing lambda into a function pointer you would lose everything that had been captured. The situation is similar to that of pointers to member functions. A pointer to a member function is useless unless you have an object to call it on.
What you are essentially saying is that you want to capture a lambda from a capturless lambda, but that doesn't make sense, because if it captures it's no longer capturless.
Update: After reading more carefully that is actually not what you are saying. You can indeed use global and static variables from lambdas without capturing them but you need to be a bit careful with that. Your latest example above would not work if that piece of code was executed more than once because the static_lambda would contain a dangling reference to an old version of c that no longer exist.