7

I'm working through setting up a member function as a callback for a C-library that I'm using. The C-library sets up callbacks like this:

typedef int (*functionPointer_t)(myType1_t*, myType2_t*, myType3_t*);

setCallback(param1, param2, functionPointer, param4)

I would like to use boost::bind (if possible) to pass in the function pointer. I would prefer that the function being pointed to was a member of the instantiated class, not a static member. E.g.

Class A {
 public: 
  A();
 protected:
  int myCallback(myType1_t*, myType2_t*, myType3_t*); //aka functionPointer_t
}

Can this be done using boost::bind and boost::function? Per How can I pass a class member function as a callback? (the 3rd answer) it appears that I could declare the following (somewhere, or as a typedef):

boost::function<int (A*, myType1_t*, myType2_t*, myType3*> myCallbackFunction

And then somewhere in A (the ctor) call boost::bind on that type, and pass it into the C-library call.

Is this possible, or am I off base? Thanks much.

Community
  • 1
  • 1
jdt141
  • 4,993
  • 6
  • 35
  • 36

3 Answers3

5

No. Functor types like boost::function don't convert to function pointers for use with C callback mechanisms.

However, most C callback mechanisms have some kind of token mechanism, so your callback function (which is static) has some kind of context information. You can use this to write a wrapper class which maps these tokens to functor objects, and passes execution along to the right one:

class CallbackManager {
public:
    typedef boost::function<int (type1*, type2*, type3*)> callback;

    static void setCallback(CallbackManager::callback cb)
    {
        void *token = ::setCallback(staticCallback);
        callbacks[token] = callback_I;
    }

    static void staticCallback(void* token, type1* a, type2* b, type3* c)
    { return mcallbacks[token](a, b, c); }

private:
    static std::map<void*, callback > callbacks;
};
Ben Straub
  • 5,675
  • 3
  • 28
  • 43
  • I can't change the interface of setCallback – jdt141 Jan 04 '10 at 19:59
  • @ jdt141: Can you abuse one of `param1, param2, param4` in `setCallback` to sneak in a token that will be returned back to you via `int (*functionPointer_t)(myType1_t*, myType2_t*, myType3_t*)` ? – Emile Cormier Jan 10 '10 at 22:28
  • Emile - totally missed your comment. I believe that I can but this method described above has worked well for me so far – jdt141 Sep 13 '10 at 23:31
1

do not use map, it gives runtime overhead and clutter up code with static map.

use reinterpret_cast instead.

for instance

// clib.h
typedef void (*CALLBACK_FUNC)(int code,void *param);

void set_callback( CALLBACK_FUNC, void * param ); 

// a.h

class A {
public:
    A()
    {
        ::set_callback( &A::static_callback, this);
    }
private:
    static void static_callback(int code, void * param)
    { 
        A* self = reinterpret_cast<A*>(param);
        self->callback( code );
    }

    inline void callback( int code )
    {
        // write you code here.
    }
};
theambient
  • 95
  • 3
0

The problem with member functions is that they automatically receive a pointer to object instance as the first parameter - "this" pointer. That's why you can't use member functions a C callback functions. You must have the object AND the function pointer together in order to use a member function.

Budric
  • 3,599
  • 8
  • 35
  • 38
  • That doesn't make sense. If that were true, I wouldn't be able to demote a boost::function to a raw pointer per http://stackoverflow.com/questions/282372/demote-boostfunction-to-a-plain-function-pointer – jdt141 Jan 04 '10 at 19:58
  • You actually can, but it's complicated. This: `A a; a.call();` is equivalent to this: `A a; A::call(&a);` as per the C++ specification, I believe. The problem is that a raw function pointer can't bring along the `this` pointer with it. – Ben Straub Jan 04 '10 at 20:06
  • thank you! that explains a lot. simply got too focused on one approach and didn't take the obvious route. – jdt141 Jan 05 '10 at 01:32