Graviton
Graviton

Reputation: 83264

Use class member functions as callbacks?

I would need a member function to be passed into a third party external method:

box_self_intersection_d(mycallback);

The box_self_intersection_d is a third party external static method, and I cannot modify it. mycallback is a method I want to pass it into the box_self_intersection_d, it is a class function and is accessing some members in this class ( have full control for this class and the mycallback)

Is there anyway I can use class member functions as callbacks without declaring them as static functions?

Edit: the signature of mycallback is (const box &boxA, const box &boxB), where box is a special class from the third party provider.

And the signature for box_self_intersection_d is

void box_self_intersection_d(RandomAccessIterator begin,RandomAccessIterator end,Callback callback)

Upvotes: 3

Views: 578

Answers (6)

Martin James
Martin James

Reputation: 24867

There is a horrible solution that I can conceive of that means copying/pushing 'this' and function code to the calling stack, (or some other caller-allocated segment that can be made writeable and executable), and passing the address of the function to the library. The called-back function could then find its own code address, extract 'this' using an offset/pointer arith. and call a member function. Should work for multiple threads.

I hereby claim this years 'Gruesome Hack' award for a solution that makes developers feel physically ill but might still actually work if a project manager is pointing a shotgun at your head.

Rgds, Martin

Upvotes: 0

molbdnilo
molbdnilo

Reputation: 66431

Since it's CGAL, the callback is actually a template parameter.
Its only constraints are "Callback must be of the BinaryFunction concept".
That is, it can be anything that is "callable" with the proper parameters.

This includes any object with a void operator() (const box&, const box&) member function.
Implementing that function in your class and passing *this for the callback would probably be the simplest solution.

Upvotes: 0

Grim Fandango
Grim Fandango

Reputation: 2426

You haven't provided the signature box_self_intersection_d()

in general, if the signature is

void box_self_intersection_d( void *cb );

or even

void box_self_intersection_d( void (*cb)(const box&, const box&) );

then you cannot pass it a pointer to a member function.

The reason is that sizeof(a_member_function) is different than sizeof(a_function_pointer). If this is the case, I think you are forced to use thiton's solution, and create a static function.

Upvotes: 0

thiton
thiton

Reputation: 36049

If the callback accepts a void* for user-defined data, you can use a static wrapper function that casts the void* argument to the class type and calls your member function.

Example:

static void Foo::callback_method(void* data) {
    static_cast<Foo*>(data)->mycallback();
}

void Foo::register_my_callback() {
    box_self_intersection_d(&Foo::callback_method, this);
}

Most sane callback libraries allow you to pass this void* argument to the functions as a way to have user-defined data in it. If not, you'll need to resort to the dirty method:

static Foo* Foo::callback_object;
static void Foo::callback_method() {
    callback_object->mycallback();
}

void Foo::register_my_callback() {
    callback_object = this;
    box_self_intersection_d(&Foo::callback_method);
}

In general, if you need to pass a function, there is just no other way: Either you have a data side-channel like the void*, which your library provider seems to have omitted (and is clearly a bug in the library), or you need to transport the this pointer via a global variable.

Upvotes: 1

Daniele Pallastrelli
Daniele Pallastrelli

Reputation: 2552

If the function box_self_intersection_d takes a functional as parameters, and mycallback is a method of a class MyClass, you can use boost::bind:

box_self_intersection_d( boost::bind( &MyClass::mycallback, myClassInstance ) );

where myClassInstance is the instance of the class MyClass.

Upvotes: 2

dinopmi
dinopmi

Reputation: 2673

There are a couple of possible workarounds. You can have a look here: http://www.newty.de/fpt/callback.html#member

In short, you can either:

  • declare a static "wrapper method" and pass the instance of the class to it,
  • or else store a pointer to the object as a global variable.

Hope that helps,

Upvotes: 0

Related Questions