C++ 中的简单事件系统

2024-02-19

我正在为我的游戏引擎设计一个简单的事件系统。 我想实现以下事件调度程序接口:

// Create event dispatcher.
Dispatcher dispatcher;

// Create objects b and c.
// Created objects extend base A class.
A* b = new B();
A* c = new C();

// Register b and c in dispatcher.
// I guess I should also pass member function pointer,
// but I am not sure how to do it.
// Like this; dispatcher.Add(b, &B::DoWork) ?
// Member function that I want to accept is always bool func(/*no params*/)
dispatcher.Add(b /*, member function pointer?*/);
dispatcher.Add(c /*, member function pointer?*/);

// Trigger passed functions for registered objects.
dispatcher.Trigger();

我想,我需要在调度程序中使用某种包装结构来保存 [Object, pFunc] 对。

struct Wrapper
{
   A* pObj; // Of base class A.
   // ??    // Pointer to given member function of A.
};

我不知道如何实现成员函数指针逻辑。 由于我需要它作为实时系统,因此我希望有一个相对快速的解决方案。我感谢所有的建议。

我宁愿避免使用第三方库。


根据评论,您可以使用std::function或类似于所提议的结构here http://blog.molecular-matters.com/2011/09/19/generic-type-safe-delegates-and-events-in-c/.
它遵循第二个建议的最小可行示例:

class Dispatcher {
    Dispatcher() { }

    template<class C, void(C::*M)() = C::receive>
    static void invoke(void *instance) {
        (static_cast<C*>(instance)->*M)();
    }

public:
    template<class C, void(C::*M)() = &C::receive>
    static Dispatcher create(C *instance) {
        Dispatcher d;
        d.fn = &invoke<C, M>;
        d.instance = instance;
        return d;
    }

    void operator()() {
        (fn)(instance);
    }

private:
    using Fn = void(*)(void *);
    Fn fn;
    void *instance;
};

struct S {
    void receive() { }
};

int main() {
    S s;
    Dispatcher d = Dispatcher::create(&s);
    d();
};

请注意,它必须根据您的要求进行相应修改(目前,目标成员方法没有返回值并且不接受参数)。
此外,它可以轻松扩展以存储目标成员方法的数组,这就是您所寻找的:只需存储成对的向量instances and invoke功能。
此外,您可以将可变参数模板与Dispatcher功能使其更加灵活。这样,您就可以定义Dispatcher具有不同的返回类型和参数列表。

EDIT

它遵循一个示例Dispatcher接受多个目标成员函数。
通过如上所述的可变参数模板来扩展它仍然很容易。

#include <vector>
#include <utility>

class Dispatcher { 
    template<class C, void(C::*M)() = C::receive>
    static void invoke(void *instance) {
        (static_cast<C*>(instance)->*M)();
    }

public:
    template<class C, void(C::*M)() = &C::receive>
    void bind(C *instance) {
        auto pair = std::make_pair(&invoke<C, M>, instance);
        targets.push_back(pair);
    }

    void operator()() {
        for(auto pair: targets) {
            (pair.first)(pair.second);
        }
    }

private:
    using Fn = void(*)(void *);
    std::vector<std::pair<Fn, void*>> targets;
};

struct S {
    void receive() { }
};

struct T {
    void receive() { }
};

int main() {
    S s;
    T t;
    Dispatcher d;
    d.bind(&s);
    d.bind(&t);
    d();
};

请注意,在上面的示例中,不能保证提交的指针为instance一旦实际使用仍然有效。您应该关注绑定对象的生命周期,或者稍微修改示例以引入更安全的句柄。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C++ 中的简单事件系统 的相关文章