Справка по указателю на функцию-член - PullRequest
0 голосов
/ 06 февраля 2010

Эй, у меня есть вопрос по поводу общих указателей на функции-члены. Я пытаюсь добиться чего-то похожего на следующий вопрос Как определить общий указатель на функцию-член

По сути, я хочу иметь возможность зарегистрировать указатель на функцию-член, которая принимает универсальный объект Event в качестве аргумента с определенным типом события (например, KeyboardEvent). Затем в своем классе управления вводом я хочу, чтобы каждый раз, когда пользователь нажимал клавишу, я мог создать объект KeyboardEvent, содержащий некоторые данные о нажатии клавиши, и вызывать все те указатели на функции-члены, которые я зарегистрировал с помощью тип KeyboardEvent с моим объектом KeyboardEvent в качестве их параметра.

Я поиграл с функциями boost bind и boost, и они, кажется, позволяют мне делать 95% того, что я хочу делать, единственная проблема, которую я пытаюсь сохранить все указатели на функции-члены в векторе, но все они разных типов, поэтому я не могу этого сделать. Поэтому я связываю их в объект функции, когда впервые регистрирую метод в моей системе обработки событий, которая ожидает от меня указания всех аргументов в этот момент выполнения. На данном этапе мне не нужно ничего делать с объектами, так как объекты генерируются каким-то неизвестным событием в будущем.

Извините, если ничего из этого не имеет смысла.

Ответы [ 3 ]

3 голосов
/ 06 февраля 2010

(Вот более прямой ответ на вашу проблему boost :: function / bind, без всяких вещей Boost.Signals2.)

Кажется, вы не используете заполнители _1, _2 и т. Д. При использовании boost :: bind. Этот пример иллюстрирует, как вы должны их использовать:

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);
}
0 голосов
/ 06 февраля 2010

Это на самом деле не ответ на вашу проблему, а лишь намек на то, что вы пытаетесь достичь, уже существует.

Похоже, вы пытаетесь реализовать шаблон Observer. Вы можете прочитать об этом здесь . Как только вы поймете шаблон Observer, проверьте библиотеку Boost.Signals2 . boost::signal подобен вектору указателей на функции обработчика событий, но гораздо более мощный.

Вот пример использования Boost :: Signals2 для обнаружения введенных символов. Надеюсь, это поможет.

#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();
    }
}
0 голосов
/ 06 февраля 2010

если я правильно понимаю ваш вопрос, вы можете попробовать

// 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, ...);
}

Я перечитал ваш вопрос и, наконец, перехватил часть функции-члена. для этого вы можете использовать функтор.

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));
...