函数指针作为 st 中的事件回调
Function Pointers as Event Callbacks in a st
我目前正在尝试实现一个事件系统,其中图层可以订阅某些事件类型。我正在努力处理回调方法的函数指针。在 layer.h 文件中,我有 OnEvent 函数和一个如下所示的函数指针:
void OnEvent(const Event& e);
void(Engine::Layer::*m_EventCallback)(const Event& e);
在层的构造函数中,我只是这样做:
m_EventCallback = OnEvent;
为了跟踪哪个层订阅了哪个 EventType,我定义了一个结构如下:
struct CallbackData {
EventType type;
void(Engine::Layer::*OnEvent)(const Event& e);
int layerID;
bool isActive;
};
我有一个 EventDispatcher,它的调度函数看起来像这样:
bool EventDispatcher::Dispatch(const Event& e)
{
for (CallbackData& calldata : m_Callbacks) {
if (calldata.type == e.GetEventType() && calldata.isActive) {
calldata.OnEvent(e);
}
}
//TODO work on this so it only returns true if the event has been properly dispatched
return true;
}
还有一个订阅函数,它创建一个 CallbackData 实例并将其推送到一个向量中,如下所示:
void EventDispatcher::Subscribe(EventType type, void(Engine::Layer::*OnEvent)
(const Event& e), int layerID)
{
CallbackData temp = { type, OnEvent, layerID, true };
m_CallbackInsert = m_Callbacks.emplace(m_CallbackInsert, temp);
}
因此,如果回调数据的类型与事件引用类型相同,则应通过函数指针调用 OnEvent 函数。
函数指针定义需要有 Engine:: ,它只是一个命名空间和 Layer ,它是 OnEvent 所在的 class 。我不知道为什么它需要命名空间,因为我在这里所做的一切都是在命名空间中定义的。
但主要问题是如何正确定义函数指针,然后按照此处展示的方式调用它?
确切的错误信息是这样的:
expression preceding parentheses of apparent call must have(pointer-to-)function type
请不要 link 网站已经实施了事件系统。我已经看过那些但并没有真正理解太多。这就是为什么我想自己做所以我明白了。
提前致谢!
假设我明白你在做什么...
您有一个 EventDispatcher,他需要保留一个可能的回调注册表。我将剪切并粘贴我使用的一些代码,然后对其进行解释。
首先,这是我的 Route 对象的相关部分。
class Route {
public:
typedef std::function<void(const HTTPServerRequest &, HTTPServerResponse &)> Callback;
Callback callback;
};
class Router {
public:
void addRoute(const std::string &method, const std::string &path, Route::Callback callback);
};
该部分按照您的预期工作,不需要任何特殊的东西。这将创建一个 Route 对象数组,回调方法被赋予回调传递给 addRoute()。当我想在这条特定路线上派遣时:
route->callback(request, response);
你可能也知道那部分。
对于我的代码,我正在对一个对象进行方法调用。要通过它,您有两种选择。第一个是使用 std::bind()——我真的不喜欢它。
所以我使用 lambdas。
addRoute("GET", "/ping", [=](const HTTPServerRequest &request, HTTPServerResponse &response) { ping(request, response); } );
这绝对是最高效的吗?我不知道。但是性能不是很糟糕,所以这就是我所做的。
基本上,我保留了 std::function<> 指针,它们真的很容易使用。只要签名匹配,您就可以将 lambda 作为 std::function<> 传递。
另一种选择是使用 std::bind——正如我所说,我不喜欢它,主要是因为我认为它比使用 lambda 更难看。但这绝对是一种观点,而不是事实。使用 std::bind 可能是更好的方法,但我没有任何代码可以向您展示如何这样做。
我不完全确定这是否真的解决了您的困惑,但如果差不多,请发表评论,我会尽力澄清。
我目前正在尝试实现一个事件系统,其中图层可以订阅某些事件类型。我正在努力处理回调方法的函数指针。在 layer.h 文件中,我有 OnEvent 函数和一个如下所示的函数指针:
void OnEvent(const Event& e);
void(Engine::Layer::*m_EventCallback)(const Event& e);
在层的构造函数中,我只是这样做:
m_EventCallback = OnEvent;
为了跟踪哪个层订阅了哪个 EventType,我定义了一个结构如下:
struct CallbackData {
EventType type;
void(Engine::Layer::*OnEvent)(const Event& e);
int layerID;
bool isActive;
};
我有一个 EventDispatcher,它的调度函数看起来像这样:
bool EventDispatcher::Dispatch(const Event& e)
{
for (CallbackData& calldata : m_Callbacks) {
if (calldata.type == e.GetEventType() && calldata.isActive) {
calldata.OnEvent(e);
}
}
//TODO work on this so it only returns true if the event has been properly dispatched
return true;
}
还有一个订阅函数,它创建一个 CallbackData 实例并将其推送到一个向量中,如下所示:
void EventDispatcher::Subscribe(EventType type, void(Engine::Layer::*OnEvent)
(const Event& e), int layerID)
{
CallbackData temp = { type, OnEvent, layerID, true };
m_CallbackInsert = m_Callbacks.emplace(m_CallbackInsert, temp);
}
因此,如果回调数据的类型与事件引用类型相同,则应通过函数指针调用 OnEvent 函数。 函数指针定义需要有 Engine:: ,它只是一个命名空间和 Layer ,它是 OnEvent 所在的 class 。我不知道为什么它需要命名空间,因为我在这里所做的一切都是在命名空间中定义的。 但主要问题是如何正确定义函数指针,然后按照此处展示的方式调用它?
确切的错误信息是这样的:
expression preceding parentheses of apparent call must have(pointer-to-)function type
请不要 link 网站已经实施了事件系统。我已经看过那些但并没有真正理解太多。这就是为什么我想自己做所以我明白了。
提前致谢!
假设我明白你在做什么...
您有一个 EventDispatcher,他需要保留一个可能的回调注册表。我将剪切并粘贴我使用的一些代码,然后对其进行解释。
首先,这是我的 Route 对象的相关部分。
class Route {
public:
typedef std::function<void(const HTTPServerRequest &, HTTPServerResponse &)> Callback;
Callback callback;
};
class Router {
public:
void addRoute(const std::string &method, const std::string &path, Route::Callback callback);
};
该部分按照您的预期工作,不需要任何特殊的东西。这将创建一个 Route 对象数组,回调方法被赋予回调传递给 addRoute()。当我想在这条特定路线上派遣时:
route->callback(request, response);
你可能也知道那部分。
对于我的代码,我正在对一个对象进行方法调用。要通过它,您有两种选择。第一个是使用 std::bind()——我真的不喜欢它。
所以我使用 lambdas。
addRoute("GET", "/ping", [=](const HTTPServerRequest &request, HTTPServerResponse &response) { ping(request, response); } );
这绝对是最高效的吗?我不知道。但是性能不是很糟糕,所以这就是我所做的。
基本上,我保留了 std::function<> 指针,它们真的很容易使用。只要签名匹配,您就可以将 lambda 作为 std::function<> 传递。
另一种选择是使用 std::bind——正如我所说,我不喜欢它,主要是因为我认为它比使用 lambda 更难看。但这绝对是一种观点,而不是事实。使用 std::bind 可能是更好的方法,但我没有任何代码可以向您展示如何这样做。
我不完全确定这是否真的解决了您的困惑,但如果差不多,请发表评论,我会尽力澄清。