Event-driven systems are used to reduce dependencies in large systems with many-to-many object interactions of various types. As such, they aim to pass arbitrary information between arbitrary objects. This is typically done by registering event handlers with an event_manager, using type erasure in the handler, i.e.:
void handle_some_event(event *e) {/*Downcast e to an assumed appropriate type and work with it*/}
However, suppose we wanted to implement such a system without type erasure. It seems that certain language features, particularly generics, should make it possible. The handler registration in the event_manager could be templated, i.e. (loosely):
template<typename event_type>
void event_manager::register_handler(std::function<void(event_type)> handler) {
// Implementation
}
The struggle is, what should the //Implementation of this function be? After receiving the handler, it needs to be stored in some container related to event_type. But in order to avoid type erasure, there would have to be a container per event_type.
One possible option is to use static containers in template classes, i.e.:
template<typename event_type>
class handler_container {
public:
inline static std::vector<std::function<void(event_type)>> handlers;
};
The event_manager could store and execute handlers in the corresponding handler_container<event_type>::handlers container. However, this has the obvious disadvantage that there can only really be one event_manager, given that the containers are static and thus shared across all event_managers. Perhaps this is sufficient for most applications, but it's still an ugly solution.
Are there any design patterns that would allow for a cleaner solution to this problem?