Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/126.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ C+中的简单事件系统+;_C++_Events_Game Engine - Fatal编程技术网

C++ C+中的简单事件系统+;

C++ C+中的简单事件系统+;,c++,events,game-engine,C++,Events,Game Engine,我正在为我的游戏引擎设计一个简单的事件系统。 我想实现以下事件调度器接口: // 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

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

// 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();
我想,我需要在Dispatcher中使用某种包装结构来保存[pObject,pFunc]对

struct Wrapper
{
   A* pObj; // Of base class A.
   // ??    // Pointer to given member function of A.
};
我不知道如何实现成员函数指针逻辑。 由于我需要一个实时系统,我希望一个相对快速的解决方案。我感谢所有建议


我更愿意避免使用第三方库。

如果您可以适当地构造A派生类,这样您就可以使用
process()
方法,您可以简单地使用多态分派

比如:

struct A
{
  virtual void process() = 0;
  virtual ~A() {}
}
struct B : public A
{
  virtual void process() { /* process event B... */ }
}
struct C : public A
{
  virtual void process() { /* process event C... */ }
}

dispatcher的trigger方法将为所有注册对象提供一个循环,在指针上调用
process()
方法,并让多态性调用适当的方法。

根据注释,您可以使用
std::function
或类似于建议的结构。
下面是第二个建议的一个简单且有效的示例:

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();
};

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

看。这个解决方案是第一个想到的,但它假设我们知道所有可能的事件。我的API需要灵活性,这为用户创建自己的调度器(自己的事件)和轻松注册所有参与者提供了可能性。
#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();
};