Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Captureless lambda cannot be converted to function pointer when stored in std::function

Usually, a C++ lambda without a capture should be convertable to a c-style function pointer. Somehow, converting it using std::function::target does not work (i.e. returns a nullptr), also the target_type does not match the signature type even though it seems to be the same.

Tested on VC13 and GCC 5.3 / 5.2.0 / 4.8

Minimal testing example:

#include <functional>
#include <iostream>

void Maybe() {

}

void callMe(std::function<void()> callback) {
    typedef void (*ftype)();
    std::cout << (callback.target_type() == typeid(ftype)) << std::endl;
    std::cout << callback.target<ftype>() << std::endl;
}

int main() {
    callMe([] () {});
    callMe(Maybe);
}

expected output would be

1
<address>
1
<address>

actual output

0
0
1
<address>

The question is: Why does the lambda's signature differ from the passed function?

like image 305
John Watson Avatar asked Jan 13 '16 14:01

John Watson


People also ask

Is lambda a function pointer?

Lambda expressions, even captured ones, can be handled as a function pointer (pointer to member function). It is tricky because an lambda expression is not a simple function. It is actually an object with an operator().

How do you declare a function pointer in C++?

We declare the function pointer, i.e., void (*ptr)(char*). The statement ptr=printname means that we are assigning the address of printname() function to ptr. Now, we can call the printname() function by using the statement ptr(s).

How do you pass lambda function in CPP?

Only variables that are mentioned in the lambda body are captured when a capture-default is used. To use lambda expressions in the body of a class member function, pass the this pointer to the capture clause to provide access to the member functions and data members of the enclosing class.

What can not be done with function pointers?

2. What will we not do with function pointers? Explanation: As it is used to execute a block of code, So we will not allocate or deallocate memory.


1 Answers

In your first call, std::function does not bother with decaying the lambda into a pointer, it just stores it, with its actual type (which is indeed not void()).

You can force the lambda to decay into a pointer before constructing the std::function with the latter by simply using a unary +:

callMe(+[](){});
//     ^
like image 85
Quentin Avatar answered Oct 14 '22 00:10

Quentin