Ashish Negi
Ashish Negi

Reputation: 5301

EventEmitter Class in C++ : Listener and Emitter

I am trying to implement a class that would allow listening on some events and when these emits are emitted, they would get notifications.

So i thought of using Functors,

 class MyFunctor {
    public:     
        virtual void emit() {}
            vitual void compare() {} 
 };

 class MyFunctorSpecial : public MyFunctor {
    void (*)() ab;
    public:
    MyFunctorSpecial(void (*a)()) : ab(a) {}
    void emit() { ab(); }
 };
 class EventEmitter {
   std::map<std::string, std::vector<MyFunctor> > eventMap;
   public:
    void On(const std::string &, const MyFunctor &) {
        // add to the map
    }

    void Emit(const std::string & eventName) {
        // emit the event
        // for all listeners in the vector for this event-name
         // call the emit of them. 
    }
 };

 EventEmitter emitter;
 // some function - abc()
 MyFunctorSpecial funct(abc);
 emitter.On("hello", funct);
 emitter.Emit("hello");

But now i want to pass arguments to the listeners. Like

 emitter.Emit("hello", 45, false);

I think that this information would be available to Emit() at compile time, about the data-types of the various arguments. Can i use that information to make it happen , using templates or anything.

If there is another kind of pattern for this problem? How can I do this?

Upvotes: 1

Views: 2952

Answers (2)

Rajib Chy
Rajib Chy

Reputation: 880

try this simple example as follow:

class event_manager {
    std::map<std::string, std::vector<std::function<void( std::string )>>> eventMap;
public:
    void on( const std::string &evt_name, std::function<void( std::string )> listener ) {
        auto it = eventMap.find( evt_name );
        if ( it != eventMap.end( ) ) {
            it->second.push_back( listener );
            return;
        }
        eventMap[evt_name] = std::vector<std::function<void( std::string )>>( );
        eventMap[evt_name].push_back( listener );
    };
    void emit( const std::string &evt_name, std::string data ) {
        auto evts = eventMap.find( evt_name );
        if ( evts == eventMap.end( ) ) return;
        for ( std::vector<std::function<void( std::string )>>::iterator it = std::begin( evts->second ); it != std::end( evts->second ); ++it ) {
            auto &func = *it;
            func( data );
        }
    }
};

and subscribe and emit event as like:

event_manager evt_mng;
evt_mng.on( "data", [&]( auto res ) { 
  std::cout << res << std::endl;
} );
evt_mng.emit( "data", "Hello world" );

Upvotes: 1

Stephane Rolland
Stephane Rolland

Reputation: 39916

The common design pattern for your problem is called the Observer Design-Pattern.

enter image description here

Your so called "functors" are not functors. If so they would have implemented an operator () method, and could have been called like functions ( thus the name functor). Yours are not.

For example, this is a functor: ( notice the operator())

class MyFunctor 
{
    public:     
        void operator()(){};
};

Upvotes: 4

Related Questions