This is a bit of a doozy and needs some explanation. I'm sorry in advance if I mess up the semantics or if I misunderstand something- I'm no beginner to C++ but some of its more advanced features I have yet to fully wrap my head around.
I'm writing language bindings from a library in C++ (although I am using the C API for this library since it's compiled with MSVC and I'm using MinGW) and I need to write up a binding for callbacks using function pointers. Even if I was using the C++ API, this would be a problem.
Luckily for me, the language I am writing bindings for Ruby (it doesn't really matter, I'm pretty sure other languages have similar C API bindings and this is language agnostic anyway) allows me to get an anonymous function useful for callbacks, in the form of a VALUE.
It's easy enough for me to wrap up these callbacks in a lambda which I can get a function pointer to, like so:
/* This is just a function that is bound to Ruby. It doesn't really matter much. */
VALUE set_some_callback(VALUE callback)
{
/* The types here don't really matter */
/* Create the lambda */
auto lambda = [callback](){
/* Run the callback, the semantics don't matter a lot here */
rb_funcall(callback, rb_intern("call"), 0);
}
/* Takes a function pointer (something like (void*)()) */
library_set_some_callback(fn);
return Qnil; // Return nil
}
This works just fine, in fact I've written bindings for other libraries that do something like this. However, this won't work for the particular library I'm writing bindings for since it exposes callbacks you've set in a struct.
/* Again, semantics don't matter here, this is for sake of example */
typedef struct Foo
{
int data;
(void*)() callback;
} Foo;
This is where the problem lies.
I can bind data (or whatever equivalent) just fine, but I can't bind the callback since it's a function pointer wrapping the actual callback. To bind the callback, I'd somehow need to extract that, and I don't know how...
I've come up with something along the lines of overloading operator() in a custom struct to wrap a callback, but I'm not sure if that's the right approach, or if it would even work.
struct BoundCallback
{
/* Store the callback */
VALUE callback;
/* Overload () */
void operator() const
{
rb_funcall(callback, rb_intern("call"), 0);
}
};
VALUE get_callback_from_foo(VALUE self)
{
/* Implementation of this doesn't matter. */
Foo foo = get_data_from(self);
/* Would this work...? */
BoundCallback callback = static_cast<BoundCallback>(foo.callback);
/* Would this work too? */
return callback.callback;
}
What's the best way to go about solving this problem?