Soylent Graham
Soylent Graham

Reputation: 978

How can I expand this C++11 event system to handle multiple arguments?

I've written a simple subscriber event system taking advantage of std::function. It works great! (and I can do some big enhancements later with thread-pooling for expensive callbacks)

The next step to improve this is to handle events/callbacks with more than one parameter.

Other than forcing structs/classes or using std::tuples in the callback arguments (I want to keep the functions clean or use existing simple funcs). Is there a good way to do this, and have multiple template parameters all with the same code?

#pragma once

#include <mutex>
#include <vector>


template<typename PARAM>
class SoyEvent
{
public:
    typedef std::function<void(PARAM&)> FUNCTION;

public:
    //  helper for member functions
    template<class CLASS>
    void            AddListener(CLASS& This,void(CLASS::*Member)(PARAM&))
    {
        //  http://stackoverflow.com/a/7582576
        auto bound = std::bind( Member, &This, std::placeholders::_1  );
        AddListener( bound );
    }
    template<class CLASS>
    void            RemoveListener(CLASS& This,FUNCTION Member)
    {
        RemoveListener( std::bind( &Member, &This ) );
    }

    //  add static or lambda
    void            AddListener(FUNCTION Function)
    {
        std::lock_guard<std::mutex> lock(mListenerLock);
        mListeners.push_back(Function);
    }
    void            RemoveListener(FUNCTION Function)
    {
        std::lock_guard<std::mutex> lock(mListenerLock);
        mListeners.erase(Function);
    }

    void            OnTriggered(PARAM& Param)
    {
        std::lock_guard<std::mutex> lock(mListenerLock);

        //  todo: execute on seperate threads with a scheduler which can just execute std::functions
        for ( auto it=mListeners.begin();   it!=mListeners.end();   it++ )
        {
            auto& Function = *it;
            Function( Param );
        }
    }

private:
    std::mutex      mListenerLock;
    std::vector<FUNCTION>   mListeners;
};

Upvotes: 2

Views: 1203

Answers (1)

Thomas Russell
Thomas Russell

Reputation: 5980

Why not just use variadic templates, i.e. change your class definition from:

template <typename PARAM>
class SoyEvent {
     // Implementation
};

To something like:

template <typename... PARAMS>
class SoyEvent {
     // Implementation
};

And then change your FUNCTION typedef to:

typedef std::function<void(PARAMS&...)> FUNCTION;

And in general change all instances of PARAM& to PARAMS&....

Upvotes: 3

Related Questions