views:

317

answers:

3

Hey, I've got a question about general member function pointers. I'm trying to achieve something similar to the following question How to define a general member function pointer

Essentially what I want to be able to do is to register a member function pointer that accepts a generic Event object as its argument with a specific event type (for example, a KeyboardEvent). Then, in my input management class, what I want to be able to do is whenever the user hits a key, I can create a KeyboardEvent object that contains some data about the keypress, and call all of those member function pointers that I registered with the KeyboardEvent type with my KeyboardEvent object as their parameter.

I've been playing around with boost bind and boost function and they seem to enable me to do 95% of what I want to do, the only problem I am trying to store all of the member function pointers in a vector, but they're all of different types so I can't do that. So I bind them into a function object when I first register the method with my event handling system, which expects me to specify all of the arguments at this point in the execution. I don't have to objects at this point though as the objects are generated by some unknown event in the future.

Sorry if none of this makes any sense.

A: 

if I understand your question correctly, you can try following

// function pointer, function with similar signature can be cast as function_t
typedef int (*function_t)(object_t *event, ...);
std:: vector<function_t> function_pointers;

// populate vector, e.g. function_pointers.push_back((function_t)&some_function)

void handle_event(object_t *event) {
  for (...) (function_pointers.at(i))(event, ...);
}

I reread your question, and finally caught member function part. for this you can use functor.

struct base {
  virtual void function(event_t *event)= 0;
};

template<class A>
struct F : base { 
  F(A &a) : object_(a) {}
  virtual void function(event_t *a) { object_.function(a); }
  A &object_;
};

std:: vector<base*> callback_vector;
...
callback_vector.push_back(new F<event_handler>(event_handler_object));
aaa
A: 

This is not really an answer to your problem, but merely a hint that what you're trying to accomplish already exists.

It seems like you're trying to implement the Observer pattern. You can read about it here. Once you've grasped the Observer pattern, check out the Boost.Signals2 library. A boost::signal is like a vector of event handler function pointers, but much more powerful.

Here is an example of using Boost::Signals2 for detecting inputted characters. Hope it helps.

#include <iostream>
#include <boost/signals2.hpp>
#include <boost/bind.hpp>

//-----------------------------------------------------------------------------
struct KeyboardEvent
{
    char key;
};

//-----------------------------------------------------------------------------
class Keyboard
{
private:
    typedef boost::signals2::signal<void (KeyboardEvent)> SignalType;
    SignalType signal_;

public:
    typedef SignalType::slot_type SlotType;

    // Subscribes to keyboard events
    boost::signals2::connection connect(const SlotType& slot)
    {
        return signal_.connect(slot);
    }

    // Scans for keyboard events and notifies subscribers
    void scan()
    {
        KeyboardEvent event;
        std::cin >> event.key;
        signal_(event);
    }
};

//-----------------------------------------------------------------------------
class KeyPrinter
{
private:
    void onKey(KeyboardEvent event)
    {
        std::cout << "You hit \'" << event.key << "\'\n";
    }

    boost::signals2::connection connection_;

public:
    void connect(Keyboard& keyb)
    {
        connection_ = keyb.connect(
            boost::bind(&KeyPrinter::onKey, this, _1) );
    }
    void disconnect() {connection_.disconnect();}
};

//-----------------------------------------------------------------------------
class Quitter
{
private:
    void onKey(KeyboardEvent event)
    {
        if (event.key == 'q' || event.key == 'Q') {quit_ = true;}
    }

    boost::signals2::connection connection_;
    bool quit_;

public:
    void connect(Keyboard& keyb)
    {
        quit_ = false;
        connection_ = keyb.connect(
            boost::bind(&Quitter::onKey, this, _1) );
    }
    void disconnect() {connection_.disconnect();}
    bool quitDetected() {return quit_;}
};

//-----------------------------------------------------------------------------
int main()
{
    Keyboard keyb;
    KeyPrinter printer;
    Quitter quitter;

    printer.connect(keyb);
    quitter.connect(keyb);

    while (!quitter.quitDetected())
    {
        keyb.scan();
    }
}
Emile Cormier
+2  A: 

(Here's a more direct answer to your boost::function/bind problem, without all the Boost.Signals2 stuff.)

It seems you're not using the _1, _2, etc. placeholders when using boost::bind. This example illustrates how you should use them:

struct KeyboardEvent { char key; };

typedef boost::function<void (KeyboardEvent)> KeyboardHandler;

struct Handler
{
    void onKey(KeyboardEvent event) {std::cout << event.key;}
};

int main()
{
    Handler handler1, handler2;
    std::vector<KeyboardHandler> handlers;
    handlers.push_back(boost::bind(&Handler::onKey, &handler1, _1));
    handlers.push_back(boost::bind(&Handler::onKey, &handler2, _1));
    KeyboardEvent event;
    event.key = 'z';
    handlers[0](event);
    handlers[1](event);
}
Emile Cormier
Wow, this did it. I tried this earlier, but it wasn't compiling. I must have been doing something else wrong. Thanks a lot for the help. And thanks for the link to the observer pattern. I'll have to read up on that. I didn't realise it already existed in C++. I was just modelling the design after Actionscript 3 events.
Morgan