2015-04-03 4 views
1

Я иду из C# и пытаюсь реализовать простой шаблон Event/EventHandler в C++ 11, который, как я полагаю, является общим именем Observer и сигналами, я знаю, что есть библиотека boost и другие, но я не хочу использовать любые внешние библиотеки.C++ 11 Наблюдатели Параметры пропуска на Notify

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

Моя проблема заключается в том, что параметры передаются при регистрации событий/наблюдателей, а не при повышении/передаче/уведомлении, которые я нахожу немного неудобными.

class EventManager 
{ 
private: 

static std::map<EventType, std::vector<std::function<void()>>> _eventHandlers; 

public: 
EventManager() = default; 


template <typename EventHandler> 
static void RegisterEventHandler(EventType&& eventType, EventHandler&& eventHandler) 
{ 
    EventManager::_eventHandlers[std::move(eventType)].push_back(std::forward<EventHandler>(eventHandler)); 
} 

static void Raise(const EventType& event) 
{ 
    for (const auto& eventHandler : EventManager::_eventHandlers.at(event)) 
    { 

     eventHandler(); 
    } 
} 

// disallow copying and assigning 
EventManager(const EventManager&) = delete; 
EventManager& operator=(const EventManager&) = delete; 


}; 

Может ли кто-нибудь помочь мне расширить следующий код, добавив функциональность для приема параметров при поднятии события?

ответ

1

Я считаю, что это решает ваш вопрос:

// g++ -std=c++11 -o /tmp/events /tmp/events.cpp && /tmp/events 
// handler=1 arg=1 
// handler=2 arg=1 
// handler=1 arg=2 
// handler=2 arg=2 

#include <functional> 
#include <map> 
#include <vector> 

template<class EventType, class... HandlerArgs> 
class EventManager 
{ 
public: 
    using EventHandler = std::function< void(HandlerArgs...) >; 

    void register_event(EventType&& event, EventHandler&& handler) 
     { 
      _handlers[std::move(event)].push_back(std::forward<EventHandler>(handler)); 
     } 

    void raise_event(const EventType& event, HandlerArgs&&... args) 
     { 
      for (const auto& handler: EventManager::_handlers.at(event)) { 
       handler(std::forward<HandlerArgs>(args)...); 
      } 
     } 

private: 
    std::map<EventType, std::vector<EventHandler>> _handlers; 

}; 

int main(int argc, char **argv) 
{ 
    EventManager<int, int> m; 
    m.register_event(1, [](int arg) { printf("handler=%d arg=%d\n", 1, arg); }); 
    m.register_event(1, [](int arg) { printf("handler=%d arg=%d\n", 2, arg); }); 
    m.raise_event(1, 1); 
    m.raise_event(1, 2); 
} 

PS: Я удалил весь код в отношении не-copiability и такие, так как она не имеет отношения к этому вопросу.

+0

спасибо за ответ, но это не сработает, если методы статичны, так как вам нужно инициализировать класс EventManager и определить шаблоны параметров/параметров для обработчиков событий, правильно? – Ronny

+0

Использование статических методов и статического члена '_handlers' будет работать отлично. –

+0

ok Спасибо, я попытаюсь изменить код и вернуться к вам, если у вас возникнут проблемы, если вы не возражаете, однако, плохо отмечайте свой ответ как правильный, поскольку вы вкладываете время и силы, чтобы помочь мне, оценили, спасибо. – Ronny

0

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

Да, я знаю, что это не лучший подход, но поскольку я не эксперт в C++, и этот вопрос не получил никаких комментариев и ответов, так что это подход im follow.