函数指针作为 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;
}

还有一个 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 可能是更好的方法,但我没有任何代码可以向您展示这样做的方式。

我不完全确定这是否真的解决了您的困惑,但如果接近,请发表评论,我会尽力澄清。