title: Using CRTP with std::tuple and variadic templates
body: <p>I want to store an <em>arbitrary number of <strong>different</em></strong> classes (all shared-pointered) in some manager-class. The different classes have to be derived from the same CRTP-interface-class. Finally, I want to be able to iterate over all stored classes and calling some functions of the interface. I do not want to create a common base class and I want only use compile-timed stuff.</p>
  
  <p>So I read a few articles in the internet and stole some concepts together. Now I have a working solution (I hope, I am new to templates in C++!), but I think, that is by far  too much overkill for such a "simple" requirement. </p>
  
  <p><em>Can you plz help me to optimize (simplify/shrink/modify) the following minimal example or provide some smarter solution? (no boost and only C++11/14/17)</em></p>
  
  <pre><code>#include &lt;iostream&gt;
  #include &lt;tuple&gt; 
  #include &lt;memory&gt;
  
  template &lt;class T_IMPLEMENTATION&gt;
  struct ISystem {
      bool run(int i) { return static_cast&lt;T_IMPLEMENTATION*&gt;(this)-&gt;runImpl(i); }
  };
  
  struct SystemA : public ISystem&lt;SystemA&gt; {
      friend ISystem&lt;SystemA&gt;;
  private:
      bool runImpl(int i) { std::cout &lt;&lt; this &lt;&lt; " A:" &lt;&lt; i &lt;&lt; std::endl; return i; };
  };
  
  struct SystemB : public  ISystem&lt;SystemB&gt; {
      friend ISystem&lt;SystemB&gt;;
  private:
      bool runImpl(int i) { std::cout &lt;&lt; this &lt;&lt; " B:" &lt;&lt; i &lt;&lt; std::endl;  return i; };
  };
  
  template&lt;typename... ARGS&gt;
  struct SystemManager {
      template &lt;int index, typename... Ts&gt;
      struct runSystem {
          void operator()(std::tuple&lt;Ts...&gt;&amp; t, int i) {
              std::get&lt;TUPLE_SIZE - index - 1&gt;(t)-&gt;run(i++);
              runSystem&lt;index - 1, Ts...&gt;{}(t, i);
          }
      };
  
      template &lt;typename... Ts&gt;
      struct runSystem&lt;0, Ts...&gt;  {
          void operator()(std::tuple&lt;Ts...&gt;&amp; t, int i) {
              std::get&lt;TUPLE_SIZE - 1&gt;(t)-&gt;run(i);
          }
      };
  
      template &lt;typename...SPTR_ARGS&gt;
      void addSystems(SPTR_ARGS...args) {
          m_tupleSystems = std::make_tuple(args...);
      }
  
      void run() {
          m_value = 0;
          runSystem&lt;TUPLE_SIZE - 1, std::shared_ptr&lt;ISystem&lt;ARGS&gt;&gt;...&gt;{}(m_tupleSystems, m_value);
      }
  private:
      using TUPLE_TYPE = std::tuple&lt;std::shared_ptr&lt;ISystem&lt;ARGS&gt;&gt;...&gt;;
      static constexpr auto TUPLE_SIZE = std::tuple_size&lt;TUPLE_TYPE&gt;::value;
      TUPLE_TYPE m_tupleSystems;
      int m_value;
  };
  
  int main() {
      auto sptrSystemA = std::make_shared&lt;SystemA&gt;();
      auto sptrSystemB = std::make_shared&lt;SystemB&gt;();
  
      SystemManager&lt;SystemA, SystemB&gt; oSystemManager;
      oSystemManager.addSystems(sptrSystemA, sptrSystemB);
      oSystemManager.run();
      return 0;
  }
  </code></pre>