2015-12-08 2 views
2

Я разрабатываю простую систему событий для своего игрового движка. Я хочу реализовать следующий интерфейс диспетчера событий:Простая система событий в C++

Я думаю, Im будет нужно какое-то обертка структуры внутри Диспетчера, чтобы держать [pObject, pFunc] пару.

struct Wrapper 
{ 
    A* pObj; // Of base class A. 
    // ?? // Pointer to given member function of A. 
}; 

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

Я бы предпочел избегать сторонних библиотек.

+3

Посмотрите на [std :: function] (http://en.cppreference.com/w/cpp/utility/functional/function). –

+2

[This] (http://blog.molecular-matters.com/2011/09/19/generic-type-safe-delegates-and-events-in-c/) также может быть хорошим моментом, из которого можно Начало. – skypjack

ответ

3

Согласно комментариям, вы можете использовать либо std::function, либо структуру, похожую на предлагаемую here.
следует, минимальный и рабочий пример второго предложения:

class Dispatcher { 
    Dispatcher() { } 

    template<class C, void(C::*M)() = C::receive> 
    static void invoke(void *instance) { 
     (static_cast<C*>(instance)->*M)(); 
    } 

public: 
    template<class C, void(C::*M)() = &C::receive> 
    static Dispatcher create(C *instance) { 
     Dispatcher d; 
     d.fn = &invoke<C, M>; 
     d.instance = instance; 
     return d; 
    } 

    void operator()() { 
     (fn)(instance); 
    } 

private: 
    using Fn = void(*)(void *); 
    Fn fn; 
    void *instance; 
}; 

struct S { 
    void receive() { } 
}; 

int main() { 
    S s; 
    Dispatcher d = Dispatcher::create(&s); 
    d(); 
}; 

Заметьте, что он должен быть соответствующим образом изменен с вашими требованиями (в настоящее время, целевой метод член не имеет возвращаемого значения и не принимает аргументов).
Кроме того, он может быть легко расширен, чтобы хранить массив методов-членов-мишеней, вот что вы искали: просто сохраните вектор пар instance s и invoke функций.
Кроме того, вы можете использовать вариационный шаблон с функцией Dispatcher, чтобы он был более гибким. Таким образом, вы сможете определить Dispatcher с разными типами возвращаемых типов и списков аргументов.

РЕДАКТИРОВАТЬ

Отсюда следует пример Dispatcher, который принимает более чем одну функцию целевого члена.
Чтобы расширить его с помощью вариационного шаблона, как указано выше, все еще достаточно просто.

#include <vector> 
#include <utility> 

class Dispatcher { 
    template<class C, void(C::*M)() = C::receive> 
    static void invoke(void *instance) { 
     (static_cast<C*>(instance)->*M)(); 
    } 

public: 
    template<class C, void(C::*M)() = &C::receive> 
    void bind(C *instance) { 
     auto pair = std::make_pair(&invoke<C, M>, instance); 
     targets.push_back(pair); 
    } 

    void operator()() { 
     for(auto pair: targets) { 
      (pair.first)(pair.second); 
     } 
    } 

private: 
    using Fn = void(*)(void *); 
    std::vector<std::pair<Fn, void*>> targets; 
}; 

struct S { 
    void receive() { } 
}; 

struct T { 
    void receive() { } 
}; 

int main() { 
    S s; 
    T t; 
    Dispatcher d; 
    d.bind(&s); 
    d.bind(&t); 
    d(); 
}; 

Пожалуйста, обратите внимание, что в приведенных выше примерах нет никакой гарантии, что указатель, представленный в instance все еще действует один раз на самом деле используется. Вы должны либо позаботиться о жизни ваших связанных объектов, либо немного изменить пример, чтобы ввести более безопасный дескриптор.

2

Если вы можете правильно структурировать классы, основанные на A, чтобы вы могли использовать метод process(), вы могли бы просто использовать полиморфную отправку.

Что-то вроде:

struct A 
{ 
    virtual void process() = 0; 
    virtual ~A() {} 
} 
struct B : public A 
{ 
    virtual void process() { /* process event B... */ } 
} 
struct C : public A 
{ 
    virtual void process() { /* process event C... */ } 
} 

Метод запуска вашего диспетчеру будет просто петля для всех зарегистрированных объектов, заходящих в process() метод на указателе и пусть полиморфизм вызвать соответствующий метод.

+0

Это решение первое, что приходит на ум, но предполагает, что мы знаем все возможные события. Мой API требует гибкости, что дает пользователю возможность создать своего диспетчера (его собственное мероприятие) и легко зарегистрировать всех участников. – DannyX

Смежные вопросы