Reputation: 5301
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
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
Reputation: 39916
The common design pattern for your problem is called the Observer Design-Pattern.
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