问题描述
我目前正在尝试实现一个事件系统,其中层可以订阅某些事件类型。我正在为回调方法的函数指针苦苦挣扎。在 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;
}
还有一个 subscribe 函数,它创建一个 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 所在的类。我不知道为什么它需要命名空间,因为我在这里所做的一切都是在命名空间中定义的。 但主要问题是如何正确定义函数指针,然后按照此处展示的方式调用它?
确切的错误信息是这样的:
expression preceding parentheses of apparent call must have(pointer-to-)function type
请不要将网站链接到已经实施的事件系统。我已经看过那些,并没有真正了解多少。这就是为什么我想自己做,所以我理解它。
提前致谢!
解决方法
假设我明白你在做什么...
你有一个 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() —— 我真的不喜欢。
所以我使用 lambda。
addRoute("GET","/ping",[=](const HTTPServerRequest &request,HTTPServerResponse &response) { ping(request,response); } );
这绝对是最有效的吗?我不知道。但性能并不差,所以这就是我所做的。
基本上,我保留 std::function 指针,这些指针非常易于使用。只要签名匹配,您就可以将 lambda 作为 std::function 传递。
另一种选择是使用 std::bind —— 正如我所说,我不喜欢它,主要是因为我认为它比使用 lambda 更丑陋。但这绝对是一种观点,而不是事实。使用 std::bind 可能是更好的方法,但我没有任何代码可以向您展示这样做的方式。
我不完全确定这是否真的解决了您的困惑,但如果接近,请发表评论,我会尽力澄清。