Simple event system in C++ Code Answer

Hello Developer, Hope you guys are doing great. Today at Tutorial Guruji Official website, we are sharing the answer of Simple event system in C++ without wasting too much if your time.

The question is published on by Tutorial Guruji team.

I am designing a simple event system for my game engine. I want to implement the following event dispatcher interface:

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

I guess, Im gonna need some kind of wrapper struct inside Dispatcher, to hold [pObject, pFunc] pair.

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

I dont know how to implement member function pointer logic. As I need it for a real time system, I would like prefer a relatively fast solution. I appreciate all suggestions.

I would prefer to avoid 3rd party libraries.

Answer

According with the comments, you can use either std::function or a structure similar to the one proposed here.
It follows a minimal and working example of the second suggestion:

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

Note that it has to be modified accordingly with your requirements (currently, the targeted member method has no return value and does not accept arguments).
Also, it can be easily extended to store an array of target member methods, that is what you were looking for: simply store a vector of pairs of instances and invoke functions.
In addition, you can use variadic template with the Dispatcher function to let it be more flexible. This way, you’ll be able to define Dispatchers having different return types and arguments lists.

EDIT

It follows an example of a Dispatcher that accepts more than one target member function.
To extend it by means of variadic template as above mentioned is still quite easy.

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

Please note that in the examples above there is no guarantee that the pointer submitted as instance is still valid once actually used. You should either take care of the lifetime of your bound objects or slightly modify the example in order to introduce a more safer handle.

We are here to answer your question about Simple event system in C++ - If you find the proper solution, please don't forgot to share this with your team members.

Related Posts

Tutorial Guruji