使用 std::function 和 std:bind 并派生 类 作为参数的事件管理器的 C++ 回调
C++ Callbacks for an Event Manager using std::function and std:bind with derived classes as parameters
我有以下活动经理:
AppEventManager.h
#pragma once
#define GF_BIND_FN(fn) std::bind(&fn, this, std::placeholders::_1)
struct Event
{
public:
enum EventType
{
AppQuit,
AppBackground,
WindowResize,
WindowGainFocus,
WindowLostFocus
};
EventType type = EventType::AppQuit;
Event(EventType type) : type(type) {}
};
struct WindowResizedEvent : public Event
{
public:
int width = 0;
int height = 0;
WindowResizedEvent(int width, int height) : width(width), height(height), Event(Event::EventType::WindowResize) {}
};
typedef std::function<void(Event&)> Callback;
class AppEventManager
{
public:
static void AddListener(Event::EventType type, Callback c);
template <typename T>
static void TriggerEvent(Event& event);
private:
static std::map<Event::EventType, std::vector<Callback>> listeners;
};
template<typename T>
inline void AppEventManager::TriggerEvent(Event& event)
{
std::map<Event::EventType, std::vector<Callback>>::iterator it = listeners.find(event.type);
if (it != listeners.end())
{
for (auto& callback : it->second)
{
callback(static_cast<T&>(event));
}
}
}
AppEventManager.cpp
#include "AppEventManager.h"
std::map<Event::EventType, std::vector<Callback>> AppEventManager::listeners = std::map<Event::EventType, std::vector<Callback>>();
// Store callback function for each event type
void AppEventManager::AddListener(Event::EventType type, Callback c)
{
std::map<Event::EventType, std::vector<Callback>>::iterator it = listeners.find(type);
if (it != listeners.end())
{
for (auto& callback : it->second)
{
// Check if callback exist
if (callback.target_type().hash_code() == c.target_type().hash_code())
{
return;
}
}
}
listeners[type].emplace_back(c);
}
添加监听器:
Window::Window()
{
AppEventManager::AddListener(Event::EventType::WindowResize, GF_BIND_FN(Window::WindowResized));
}
void Window::WindowResized(Event& event)
{
if (event.type == Event::EventType::WindowResize)
{
WindowResizedEvent e = reinterpret_cast<WindowResizedEvent&>(event);
windowWidth = e.width;
windowHeight = e.height;
}
}
触发事件:
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg)
{
case WM_CLOSE:
DestroyWindow(hwnd);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
case WM_SIZE:
{
WindowResizedEvent event(LOWORD(lParam), HIWORD(lParam)); <---
AppEventManager::TriggerEvent<WindowResizedEvent>(event); <---
}
break;
default:
return DefWindowProc(hwnd, msg, wParam, lParam);
}
return 0;
}
此代码有效,但如您在 void Window::WindowResized(Event& event)
中所见,我需要将事件转换为派生的 WindowResizedEvent。
我想实现的是直接用 WindowResizedEvent 参数调用 void Window::WindowResized(Event& event)
:void Window::WindowResized(WindowResizedEvent & event)
但现在不可能,因为 typedef std::function<void(Event&)> Callback;
要求参数是 Event 而不是派生自活动。
我找不到其他方法来解决这个问题,我不知道是否可行。
如果您知道实现此目的的完全不同的方法,那也没关系。
您可以为每种类型使用单独的向量。通过模板函数访问它们。
class AppEventManager
{
public:
template <typename T>
static void AddListener(std::function<void(T&)> callback) {
get_listeners<T>().push_back(std::move(callback));
}
template <typename T>
static void TriggerEvent(T& event) {
for (auto& listener : get_listeners<T>()) {
listener(event);
}
}
private:
template <typename T>
static std::vector<std::function<void(T&)>>& get_listeners() {
static std::vector<std::function<void(T&)>> listeners;
return listeners;
}
};
并直接与类型而不是枚举一起使用。
Window::Window()
{
AppEventManager::AddListener<WindowResizedEvent>(GF_BIND_FN(Window::WindowResized));
}
作为旁注,建议使用 lambda 而不是 std::bind
。
Window::Window()
{
AppEventManager::AddListener<WindowResizedEvent>([&](WindowResizedEvent& event) { WindowResized(event); });
}
我有以下活动经理:
AppEventManager.h
#pragma once
#define GF_BIND_FN(fn) std::bind(&fn, this, std::placeholders::_1)
struct Event
{
public:
enum EventType
{
AppQuit,
AppBackground,
WindowResize,
WindowGainFocus,
WindowLostFocus
};
EventType type = EventType::AppQuit;
Event(EventType type) : type(type) {}
};
struct WindowResizedEvent : public Event
{
public:
int width = 0;
int height = 0;
WindowResizedEvent(int width, int height) : width(width), height(height), Event(Event::EventType::WindowResize) {}
};
typedef std::function<void(Event&)> Callback;
class AppEventManager
{
public:
static void AddListener(Event::EventType type, Callback c);
template <typename T>
static void TriggerEvent(Event& event);
private:
static std::map<Event::EventType, std::vector<Callback>> listeners;
};
template<typename T>
inline void AppEventManager::TriggerEvent(Event& event)
{
std::map<Event::EventType, std::vector<Callback>>::iterator it = listeners.find(event.type);
if (it != listeners.end())
{
for (auto& callback : it->second)
{
callback(static_cast<T&>(event));
}
}
}
AppEventManager.cpp
#include "AppEventManager.h"
std::map<Event::EventType, std::vector<Callback>> AppEventManager::listeners = std::map<Event::EventType, std::vector<Callback>>();
// Store callback function for each event type
void AppEventManager::AddListener(Event::EventType type, Callback c)
{
std::map<Event::EventType, std::vector<Callback>>::iterator it = listeners.find(type);
if (it != listeners.end())
{
for (auto& callback : it->second)
{
// Check if callback exist
if (callback.target_type().hash_code() == c.target_type().hash_code())
{
return;
}
}
}
listeners[type].emplace_back(c);
}
添加监听器:
Window::Window()
{
AppEventManager::AddListener(Event::EventType::WindowResize, GF_BIND_FN(Window::WindowResized));
}
void Window::WindowResized(Event& event)
{
if (event.type == Event::EventType::WindowResize)
{
WindowResizedEvent e = reinterpret_cast<WindowResizedEvent&>(event);
windowWidth = e.width;
windowHeight = e.height;
}
}
触发事件:
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg)
{
case WM_CLOSE:
DestroyWindow(hwnd);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
case WM_SIZE:
{
WindowResizedEvent event(LOWORD(lParam), HIWORD(lParam)); <---
AppEventManager::TriggerEvent<WindowResizedEvent>(event); <---
}
break;
default:
return DefWindowProc(hwnd, msg, wParam, lParam);
}
return 0;
}
此代码有效,但如您在 void Window::WindowResized(Event& event)
中所见,我需要将事件转换为派生的 WindowResizedEvent。
我想实现的是直接用 WindowResizedEvent 参数调用 void Window::WindowResized(Event& event)
:void Window::WindowResized(WindowResizedEvent & event)
但现在不可能,因为 typedef std::function<void(Event&)> Callback;
要求参数是 Event 而不是派生自活动。
我找不到其他方法来解决这个问题,我不知道是否可行。
如果您知道实现此目的的完全不同的方法,那也没关系。
您可以为每种类型使用单独的向量。通过模板函数访问它们。
class AppEventManager
{
public:
template <typename T>
static void AddListener(std::function<void(T&)> callback) {
get_listeners<T>().push_back(std::move(callback));
}
template <typename T>
static void TriggerEvent(T& event) {
for (auto& listener : get_listeners<T>()) {
listener(event);
}
}
private:
template <typename T>
static std::vector<std::function<void(T&)>>& get_listeners() {
static std::vector<std::function<void(T&)>> listeners;
return listeners;
}
};
并直接与类型而不是枚举一起使用。
Window::Window()
{
AppEventManager::AddListener<WindowResizedEvent>(GF_BIND_FN(Window::WindowResized));
}
作为旁注,建议使用 lambda 而不是 std::bind
。
Window::Window()
{
AppEventManager::AddListener<WindowResizedEvent>([&](WindowResizedEvent& event) { WindowResized(event); });
}