ECS Event/Messaging implementation I am experimenting with ECS design and I am looking for a solid way to implement a message bus for use between the different systems.
Here is a stripped-down version of my current implementation:

#include &lt;iostream&gt;
#include &lt;cstdlib&gt;
#include &lt;functional&gt;
#include &lt;vector&gt;

struct BaseEvent
{
    static size_t type_count;
    virtual ~BaseEvent() {}
};

size_t BaseEvent::type_count = 0;

template &lt;typename EventType&gt;
struct Event : BaseEvent
{
    static size_t type()
    {
        static size_t t_type = type_count++;
        return t_type;
    }
};


struct EventManager
{
    template &lt;class EventType&gt;
    using call_type = std::function&lt;void(const EventType&amp;)&gt;;

    template &lt;typename EventType&gt;
    void subscribe(call_type&lt;EventType&gt; callable)
    {
        if (EventType::type() &gt;= m_subscribers.size())
            m_subscribers.resize(EventType::type()+1);
        m_subscribers[EventType::type()].push_back(
            CallbackWrapper&lt;EventType&gt;(callable));
    }

    template &lt;typename EventType&gt;
    void emit(const EventType&amp; event)
    {
        if (EventType::type() &gt;= m_subscribers.size())
            m_subscribers.resize(EventType::type()+1);
        for (auto&amp; receiver : m_subscribers[EventType::type()])
            receiver(event);

    }

    template &lt;typename EventType&gt;
    struct CallbackWrapper
    {
        CallbackWrapper(call_type&lt;EventType&gt; callable) : m_callable(callable) {}
        void operator() (const BaseEvent&amp; event) { m_callable(static_cast&lt;const EventType&amp;&gt;(event)); }
        call_type&lt;EventType&gt; m_callable;
    };

    std::vector&lt;std::vector&lt;call_type&lt;BaseEvent&gt;&gt;&gt; m_subscribers;
};


The classes are then used like so:

struct PLAYER_LVL_UP : Event&lt;PLAYER_LVL_UP&gt;
{ int new_level; };

struct PLAYER_HIT : Event&lt;PLAYER_HIT&gt;
{ int damage; };

struct COLLISION : Event&lt;COLISSION&gt;
{ Entity entity1; Entity entity2; };

struct PLAYER_GUI    
{

    PLAYER_GUI(EventManager&amp; em, ...) : ...
    {
        using namespace std::placeholders;

        em.subscribe&lt;PLAYER_HIT&gt;(
            std::bind(&amp;PLAYER_GUI::handle_hit, this, _1); 
        em.subscribe&lt;PLAYER_LVL_UP&gt;(
            std::bind(&amp;PLAYER_GUI::handle_lvl_up, this, _1);
        .
        .
    }

    void handle_hit(const PLAYER_HIT&amp; event)
    {
         // change rendering of life/player in the gui
    }

    void handle_lvl_up(const PLAYER_LVL_UP&amp; event)
    {
        // change rendering of the lvl in the gui
    }

    ...
};


struct CollisionSystem : public System&lt;CollisionSystem&gt;
{
     .
     .
     void update(EventManager&amp; em, float dt)
     {
         .
         .
         if (collides(entity1, entity2))
             em.emit(COLLISION{entity1, entity2});
     }
};


Obviously, this code snippet lacks a lot of things but at the moment I am mostly concerned with the approach taken. Specifically, I am not particularly sure about using static functions to map the event types to integers. I would really appreciate some general guidance in the right direction!
My suggestions:

Move type_count from being a public member

type_count plays an important role in the event manager. Making such a crucial part of the event management system a publically accessible member variable seems risky to me.

I would make that accessible only as a protected member function.

struct BaseEvent
{
   virtual ~BaseEvent() {}
   protected:
      static size_t getNextType();
};

size_t BaseEvent::getNextType()
{
   static size_t type_count = 0;
   return type_count++;
}


Of course, change Event appropriately.

template &lt;typename EventType&gt;
struct Event : BaseEvent
{
   static size_t type()
   {
      static size_t t_type = BaseEvent::getNextType();
      return t_type;
   } //; You don't need this semi-colon. Remove it.
};


Change the implementation of EventManager to simply event classes

Instead of 

struct PLAYER_LVL_UP : Event&lt;PLAYER_LVL_UP&gt;
{ int new_level; };

struct PLAYER_HIT : Event&lt;PLAYER_HIT&gt;
{ int damage; };

struct COLLISION : Event&lt;COLLISION&gt;
{ Entity entity1; Entity entity2; };


it's cleaner to have:

struct PLAYER_LVL_UP
{ int new_level; };

struct PLAYER_HIT
{ int damage; };

struct COLLISION
{ Entity entity1; Entity entity2; };


You can accomplish that by updating EventManager to:

struct EventManager
{
   template &lt;class EventType&gt;
      using call_type = std::function&lt;void(const EventType&amp;)&gt;;

   template &lt;typename EventType&gt;
      void subscribe(call_type&lt;EventType&gt; callable)
      {
         // When events such as COLLISION don't derive
         // from Event, you have to get the type by 
         // using one more level of indirection.
         size_t type = Event&lt;EventType&gt;::type();
         if (type &gt;= m_subscribers.size())
            m_subscribers.resize(type+1);
         m_subscribers[type].push_back(CallbackWrapper&lt;EventType&gt;(callable));
      }

   template &lt;typename EventType&gt;
      void emit(const EventType&amp; event)
      {
         // Same change to get the type.
         size_t type = Event&lt;EventType&gt;::type();
         if (type &gt;= m_subscribers.size())
            m_subscribers.resize(type+1);

         // This a crucial change to the code.
         // You construct a temporary Event object by
         // using the EventType object and use Event.
         // This requires a change to Event, which follows below.
         Event&lt;EventType&gt; eventWrapper(event);
         for (auto&amp; receiver : m_subscribers[type])
            receiver(eventWrapper);

      }

   template &lt;typename EventType&gt;
      struct CallbackWrapper
      {
         CallbackWrapper(call_type&lt;EventType&gt; callable) : m_callable(callable) {}

         void operator() (const BaseEvent&amp; event) { 
          // The event handling code requires a small change too.
          // A reference to the EventType object is stored 
          // in Event. You get the EventType reference from the
          // Event and make the final call.
          m_callable(static_cast&lt;const Event&lt;EventType&gt;&amp;&gt;(event).event_); }

         call_type&lt;EventType&gt; m_callable;
      };

   std::vector&lt;std::vector&lt;call_type&lt;BaseEvent&gt;&gt;&gt; m_subscribers;
};


The updated Event class:

template &lt;typename EventType&gt;
struct Event : BaseEvent
{
   static size_t type()
   {
      static size_t t_type = BaseEvent::getNextType();
      return t_type;
   }
   Event(const EventType&amp; event) : event_(event) {}
   const EventType&amp; event_;
};