Thread: Callbacks, allowing ptr to member with arg. binding

  1. #1
    Registered User
    Join Date
    Dec 2006
    Posts
    69

    Callbacks, allowing ptr to member with arg. binding

    I'm using a library where to I can pass a function pointer which is later called by the library. I would like to be able to pass a pointer-to-member instead of a normal function pointer to the library.

    I read somewhere that this should be possible with argument binding; binding a class instance as the first parameter.

    I've tried to use boost.bind, with no success. Here is roughly what I tried:

    someAPI->setEventFunction(x, bind(&MyClass::myFunc, this, _1, _2, _3)); // called from MyClass method

    But it says that it can't convert from the boost.bind template to a normal function pointer. Is there a solution to this, without altering the library?
    Last edited by C+/-; 04-03-2008 at 08:50 AM.

  2. #2
    Officially An Architect brewbuck's Avatar
    Join Date
    Mar 2007
    Location
    Portland, OR
    Posts
    7,396
    Quote Originally Posted by C+/- View Post
    someAPI->setEventFunction(x, bind(&MyClass::myFunc, this, _1, _2, _3)); // called from MyClass method

    But it says that it can't convert from the boost.bind template to a normal function pointer. Is there a solution to this, without altering the library?
    Looks like the setEventFunction() method is not appropriately templatized. You aren't going to be able to do it cleanly without modifying the library itself to take a template instead of a function pointer. You can solve it in a dirty way, without changing the library, by using a global variable which holds the pointer to the object you want to invoke the method on, but that does not allow concurrent calls...

    Does this setEventFunction() method provide a generic pointer argument where you could stash something? What's the exact prototype of setEventFunction()?

  3. #3
    Registered User
    Join Date
    Dec 2006
    Posts
    69
    I've written the library myself, so it's relatively easy to change.

    The exact prototype is:
    void setEventFunction(MessageID messageID, PacketHandler packetHandler);

    where PacketHandler is:
    typedef int (*PacketHandler)(unsigned char* data, unsigned int dataLength, SystemID sourceSystem);

    How could I appropriately templatize this?

  4. #4
    Officially An Architect brewbuck's Avatar
    Join Date
    Mar 2007
    Location
    Portland, OR
    Posts
    7,396
    Quote Originally Posted by C+/- View Post
    I've written the library myself, so it's relatively easy to change.

    The exact prototype is:
    void setEventFunction(MessageID messageID, PacketHandler packetHandler);

    where PacketHandler is:
    typedef int (*PacketHandler)(unsigned char* data, unsigned int dataLength, SystemID sourceSystem);

    How could I appropriately templatize this?
    The question is, do you want to? Since you have control of the library, you have two options -- make the callback a template, or alter the callback so that it accepts an opaque pointer which will allow you to pass the object through, allowing the member call.

    So, pick one and I'll go over it.

  5. #5
    Registered User
    Join Date
    Dec 2006
    Posts
    69
    I'm not sure. I don't understand what you mean by "opaque pointer". What is an opaque pointer in this context?

    Also, in order for the library to pass an object to the callback, it has to store it. But it can't know its type (or at least I don't want it to).

    I don't really understand how you want to use templates for the callback, either.

    I had this idea (and partially implemented it, not sure it's the best, though):
    Have a abstract base class EventFunction with an execute() method. Then allow the library user to create a derived class that will take an instance of the desired class, and a pointer to one of it's members in the constructor. This class' execute function can then do a member function call. Because it's a subclass, the library can use the baseclass pointer to call execute() on the derived classes.

    I'm not sure that's the best (cleanest, most performant, easyest to use for library user) method, so please expand a little on those other two possibilities you mentioned.

  6. #6
    Officially An Architect brewbuck's Avatar
    Join Date
    Mar 2007
    Location
    Portland, OR
    Posts
    7,396
    Quote Originally Posted by C+/- View Post
    I'm not sure. I don't understand what you mean by "opaque pointer". What is an opaque pointer in this context?

    Also, in order for the library to pass an object to the callback, it has to store it. But it can't know its type (or at least I don't want it to).
    Right -- that's what an opaque pointer is.

    Okay, there are three ways to deal with this, not two. The way you just suggested is the third -- instead of passing a pointer to a function, pass a pointer to an object, which implements some base interface. I.e.:

    Code:
    class event_base
    {
        virtual ~event_base() {}
    
        virtual void do_event(unsigned char* data, unsigned int dataLength, SystemID sourceSystem) = 0;
    };
    
    class my_event_handler : public event_base
    {
        virtual void do_event(unsigned char* data, unsigned int dataLength, SystemID sourceSystem)
        {
            // Do your stuff
        }
    };
    Then you create a my_event_handler, and pass it to the setEventFunction() method. This method will take an event_base pointer, not a my_event_handler pointer, and the call is virtual. Does that make sense?

    The templatized version is actually pretty complicated, and I'm thinking it's probably not the best solution in this case.

    The opaque pointer method would be as follows:

    Code:
    void setEventFunction(MessageID messageID, PacketHandler packetHandler, void *handlerData);
    With the PacketHandler modified to be:

    Code:
    typedef int (*PacketHandler)(unsigned char* data, unsigned int dataLength, SystemID sourceSystem, void *handlerData);
    So when you set the handler, you pass a pointer to the MyClass object as "handlerData" -- the handler function itself will receive this pointer as its last argument, cast it back to MyClass, and invoke whatever it needs to.

    But that's a very C-ish way of doing it. Your suggestion is actually best I think.

  7. #7
    Registered User
    Join Date
    Dec 2006
    Posts
    69
    Thanks, brewbuck. I'll go with the class hierarchy.

    One last question, though. Does the template method you where thinking about require the user of the library to create his own subclasses? If not, that would be a pretty big advantage. Is it really a worse solution, or is it just (much) more complicated?

  8. #8
    Officially An Architect brewbuck's Avatar
    Join Date
    Mar 2007
    Location
    Portland, OR
    Posts
    7,396
    Quote Originally Posted by C+/- View Post
    Question, though. Does the template method you where thinking about require the user of the library to create his own subclasses? If not, that would be a pretty big advantage. Is it really a worse solution, or is it just (much) more complicated?
    The problem is that simply templatizing the setEventFunction() member isn't enough -- you have to actually store the callback object somewhere, which means the entire class which contains setEventFunction() has to be templatized. And if there are lots of callbacks, that means it has to be templatized on lots of types, simultaneously. A solution to this would involve base classes and virtual dispatch anyway, so why complicate matters with a template.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Getting an error with OpenGL: collect2: ld returned 1 exit status
    By Lorgon Jortle in forum C++ Programming
    Replies: 6
    Last Post: 05-08-2009, 08:18 PM
  2. Help calling function is asm
    By brietje698 in forum C++ Programming
    Replies: 24
    Last Post: 12-06-2007, 04:48 PM
  3. Inline asm
    By brietje698 in forum C++ Programming
    Replies: 5
    Last Post: 11-11-2007, 02:54 PM
  4. Getting position from game..
    By brietje698 in forum C++ Programming
    Replies: 1
    Last Post: 10-26-2007, 12:15 PM
  5. Screwy Linker Error - VC2005
    By Tonto in forum C++ Programming
    Replies: 5
    Last Post: 06-19-2007, 02:39 PM