I’m trying to define a function/method (void MyClass::myDispatcher(int, int, void *) or std::function<void(int, int, void *)> myDispatcher) which would be a member of a host class.
However, I also need to pass this function to through an external library which takes as argument: void (*dispatcher) (int, int, void *).
Is there a way I can convert a non-static function to the required void (*)(int, int, void *) type ?
My first attempt with the candidate void MyClass::myDispatcher(int, int, void *) was using the std::bind() in order to bind MyClass::myDispatcher with this. Although I could not convert the return type of std::bind to match the void (*).
The second attempt was done using std::function<void(int, int, void *)> myDispatcher for which I tried to use the reinterpret_cast<void (*)(int, int, void *)>(&myDispatcher) to fit in the requested argument. It did compile but I ultimatly ended up in a segfault within the external library.
I could summarized my two attempts with this example:
class MyClass{
MyClass() = default;
void myDispatcher(int, int, void *){
// do something
}
void init(){
myFct = [this](int, int, void*){
// do something
};
external_function(reinterpret_cast<void (*)(int, int, void *)>(&myFct));
// or the non-compiling
// external_function(std::bind(&MyClass::myDispatcher, this));
}
private:
std::function<void(int, int, void*)> myFct;
};
Edit:
As some of you pointed out: this C-style external_function has an extra void * argumement which is passed as the last arg to the provided function!
To summarise: there is no way to do such a thing since there is a fundamental difference between a function pointer and non-static member functions. However, C-style library usually provides a workaround which performs a callback to the provided static function:
void external_function(void (*dispatcher) (int, int, void *), void* info){
// a bunch of instructions (meaningless for this example)
int a,b;
dispatcher(a,b,info);
}
Once we know that, one can cast back the info pointer to the class we want.
>Solution :
As stated, this is not possible since there is no way to meaningfully construct a plain function pointer from a (non static) method, a closure, or a std::function object.
Roughly speaking, each of the constructs above are logically formed by two parts: some fixed code (a pointer to a fixed, statically known function), and variable data (the object at hand, or the captures for a closure). We can not simply throw away the second part.
That being said, I would recommend to check if the library will call the dispatcher passing a user-defined pointer for its void * argument. It’s somewhat common to see C style library functions like
void register_callback(void (*dispatcher)(int,int,void *), void *user_data);
This is a trick to allow to simulate closures in C, passing the two "parts" of the closure separately.
If that’s the case, instead of
// not working, just for example
std::function<void(int, int)> f;
register_callback(f);
You can write
// Make sure f will live long enough.
// I'm using new to stress the point, but you can use anything
// else provided that the pointer will be valid when f is
// called.
std::function<void(int, int, void *)> *pf = new ...;
register_callback(call_the_function, pf);
provided you have defined
// fixed function, independent from the std::function object
void call_the_function(int x, int y, void *p) {
std::function<void(int,int,void*)> *pf =
(std::function<void(int,int,void*)>*) p;
(*pf)(x,y);
}
If you used new to keep the pointer valid long enough, remember to delete it when the callback is no longer needed.