I am working with a framework that has a C API with a typedef that looks something like this:
typedef int (*function_type)(int argc, voidptr_t args[], void *data)
and a function that takes such function pointers that looks like this:
void create_callback(function_type fn, void *data);
(if it was not obvious, voidptr_t is simply another typedef for void *)
The framework will invoke callbacks at particular times, as needed, with the argc and args parameters set up to reflect conditions that are in effect at the time. argc will never be less than 1, and the first entry in args will always be a pointer to some valid data that could be cast to a pointer to some class in my program, and could in many ways be thought of as a 'this' pointer, as it indicates the object or data that the callback is expected to act upon or use.
I will be calling this API from C++, and am wanting a way to wrap up member functions of a classes that looks like this:
class A
{
int member_fn1(int argc, voidptr_t args[], void *data);
};
class B
{
int member_fn2(int argc, voidptr_t args[], void *data);
};
Now I am wanting a way to use these member functions as callbacks.... I could do it by changing the definitions of A and B to include static functions that I could use as callbacks as follows:
class A
{
int member_fn1(int argc, voidptr_t args[], void *data);
static int call_fn1(int argc, voidptr_t args[], void *data)
{
((A*)args[0])->*fn1(argc-1,&args[1],dat
}
};
class B
{
int member_fn2(int argc, voidptr_t args[], void *data);
static int call_fn2(int argc, voidptr_t args[], void *data)
{
((B*)args[0])->fn2(argc-1,&args[1],data);
}
};
However, this will get extremely tedious if I had to define an addition such static function for every member function I wanted to use as a callback. As you can see from this, however, the idea is to only pass the other arguments into the member function, and allow the first argument to assume the value for this.
What I am wanting to do is define some kind of template function which I can pass as a parameter to create_callback, and will wrap up a member function so it can be invoked as a callback.
The wrap_function would look something like this:
template<????> int wrap_function(int argc, voidptr_t args[], void *data)
{
try {
return ((X*)args[0])->fn(argc-1, &args[1], data);
} catch(...) {
// handle any exception safely, because we can't let it get back into C code
handle_exception(std::current_exception());
return -1
}
}
where X is the typename for the class, and fn is the member function itself.
Note that this function also flexibly deals with exceptions, where I would otherwise be writing virtually identical code over and over for each member function I wanted to use as a callback... which is why I wanted to set it up as a template function.
So once I had wrap_function defined, I could define callbacks in the API by doing this:
create_callback(wrap_function<&A::member_function1>, some_data)
create_callback(wrap_function<&B::member_function2>, some_other_data)
Since the definition of wrap_function is just a regular function and not a method, I can pass its address as a regular function pointer to the C API, and the duty of the function would be to delegate its work to the correct member function in the correct class.
But how do I define the wrap_function template, exactly, to make this work?
I sincerely hope this question is clear... if anyone feels that it needs to be described better, please indicate specifically what is unclear below in a comment, so that I can improve this question.
template <typename X, int (X::*fn)(int, voidptr_t[], void*)>
int wrap_function(int argc, voidptr_t args[], void *data) {
return (static_cast<X*>(args[0])->*fn)(argc-1, &args[1], data);
}
should work, I think. You use it this way:
create_callback(wrap_function<A, &A::member_function1>, some_data)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With