    #include <iostream>
    #include <map>
    #include <vector>

    /**
    * Receiver
    */
class EBaseReceiver
{
    protected:
    static std::size_t nextId;
};

template <class TEventData>
class Receiver : public EBaseReceiver
{
    friend class EventManager;
public:
    virtual void onEventReceive( const TEventData& event ) = 0;
    static std::size_t getId() { return ID; }
private:
    static std::size_t ID;
};

/**
* Event
*/
struct BaseEvent
{
    protected:
    static std::size_t nextId;
};

template <typename T>
struct Event : public BaseEvent
{
    static std::size_t getId() { return ID; }
    static std::size_t ID;
};

/**
* EventManager
*/
class EventManager
{
private:

    typedef std::vector<EBaseReceiver*> ReceiverArray;
    typedef std::map<std::size_t, ReceiverArray> ImplSubscriberArray;
    ImplSubscriberArray subscribers;

public:

    template< class TEvent, template<class> class TReceiver>
    void subscribe( TReceiver<TEvent>* receiver )
    {
        const std::size_t eventId = TEvent::getId();
        this->subscribers[eventId].push_back(receiver);
    }

    template <typename TEvent>
    void emit( const TEvent& event )
    {
        const ReceiverArray& receivers = this->subscribers[TEvent::getId()];
        for( auto& receiver : receivers )
        {
            static_cast<Receiver<TEvent>&>((*receiver)).onEventReceive(event);
        }
    }
};

/**
* Test events
*/
EventManager eventManager;
struct HealthEvent : public Event<HealthEvent>{};
struct DamageEvent : public Event<DamageEvent>{};

/**
* Test classes
*/
class DamageSystem : public Receiver<HealthEvent>, public Receiver<DamageEvent>
{
public:
    DamageSystem() : Receiver<HealthEvent>(), Receiver<DamageEvent>()
    {
        eventManager.subscribe<HealthEvent, ::Receiver>(this);
        eventManager.subscribe<DamageEvent, ::Receiver>(this);
    }

    void onEventReceive( const HealthEvent& event ) { std::cout << "HealthEvent !" << std::endl; };
    void onEventReceive( const DamageEvent& event ) { std::cout << "DamageEvent !" << std::endl; };
};

int main()
{
    DamageSystem system;
    eventManager.emit(DamageEvent());
    return 0;
}
