C++11 观察者在 Notify 上传递参数
C++11 Observers Pass parameters on Notify
我来自 C# 并尝试在 c++11 中实现一个简单的 Events/EventHandler 模式,我相信它的通用名称是 Observers and signals,我知道有 boost 库和其他库,但我不知道想使用任何外部库。
在网上搜索时,我找到了一个简单的实现方式来满足我的需要,所以我修改了代码,它工作正常。
我的问题是参数在注册 events/observers 时传递,而不是在 raising/signaling/notifying 时传递,我觉得有点尴尬。
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;
};
任何人都可以通过添加在引发事件时接受参数的功能来帮助我扩展以下代码吗?
因为我还没有得到任何答案,所以我想出了一个方法,但我不喜欢它,因为我想要一个更好的方法,但是我创建了一个静态 class,它为每个事件都有静态变量,在引发事件之前,调用者将设置这些变量,处理程序将读取然后重置它们。这是一种危险的方法,尤其是对于多线程,因为一个或多个线程可能会在多个线程引发同一事件时更改值,因此我必须实现一些锁定功能以确保线程安全。
是的,我知道这不是最好的方法,但因为我不是 C++ 专家,而且这个问题没有得到任何评论或答案,所以这就是我遵循的方法。
我相信这可以解决您的问题:
// 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: 我删除了所有关于不可复制性等的代码,因为它与这个问题无关。
我来自 C# 并尝试在 c++11 中实现一个简单的 Events/EventHandler 模式,我相信它的通用名称是 Observers and signals,我知道有 boost 库和其他库,但我不知道想使用任何外部库。
在网上搜索时,我找到了一个简单的实现方式来满足我的需要,所以我修改了代码,它工作正常。
我的问题是参数在注册 events/observers 时传递,而不是在 raising/signaling/notifying 时传递,我觉得有点尴尬。
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;
};
任何人都可以通过添加在引发事件时接受参数的功能来帮助我扩展以下代码吗?
因为我还没有得到任何答案,所以我想出了一个方法,但我不喜欢它,因为我想要一个更好的方法,但是我创建了一个静态 class,它为每个事件都有静态变量,在引发事件之前,调用者将设置这些变量,处理程序将读取然后重置它们。这是一种危险的方法,尤其是对于多线程,因为一个或多个线程可能会在多个线程引发同一事件时更改值,因此我必须实现一些锁定功能以确保线程安全。
是的,我知道这不是最好的方法,但因为我不是 C++ 专家,而且这个问题没有得到任何评论或答案,所以这就是我遵循的方法。
我相信这可以解决您的问题:
// 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: 我删除了所有关于不可复制性等的代码,因为它与这个问题无关。