title: Extending Multi patterned variadic templates in C++
body: <p>This question is a follow on from my previous question <a href="https://stackoverflow.com/questions/50311966/multi-patterend-varadic-templates-in-c">Multi patterned varadic templates in C++</a> to which I received the solution:</p>
  
  <pre><code>#include &lt;array&gt;
  #include &lt;iostream&gt;
  #include &lt;type_traits&gt;
  
  template &lt;typename T, std::size_t N&gt;
  class Vec;
  
  template &lt;std::size_t, typename ...&gt;
  struct dimVec;
  
  // ground case for no Vecs: unimplemented for SFINAE failure !
  template &lt;&gt;
  struct dimVec&lt;0U&gt;;
  
  // ground case with one or more Vecs: size fixed
  template &lt;std::size_t N&gt;
  struct dimVec&lt;N&gt; : public std::integral_constant&lt;std::size_t, N&gt;
   { };
  
  // first Vec: size detected
  template &lt;std::size_t N, typename T, typename ... Ts&gt;
  struct dimVec&lt;0U, Vec&lt;T, N&gt;, Ts...&gt; : public dimVec&lt;N, Ts...&gt;
   { };
  
  // another Vec of same size: continue
  template &lt;std::size_t N, typename T, typename ... Ts&gt;
  struct dimVec&lt;N, Vec&lt;T, N&gt;, Ts...&gt; : public dimVec&lt;N, Ts...&gt;
   { };
  
  // another Vec of different size: unimplemented for SFINAE failure !
  template &lt;std::size_t N1, std::size_t N2, typename T, typename ... Ts&gt;
  struct dimVec&lt;N1, Vec&lt;T, N2&gt;, Ts...&gt;;
  
  // a not-Vec type: continue
  template &lt;std::size_t N, typename T, typename ... Ts&gt;
  struct dimVec&lt;N, T, Ts...&gt; : public dimVec&lt;N, Ts...&gt;
   { };
  
  template &lt;typename ... Args&gt;
  static constexpr auto dimVecV { dimVec&lt;0U, Args...&gt;::value };
  
  template &lt;std::size_t I, typename T, std::size_t N&gt;
  constexpr auto extrV (Vec&lt;T, N&gt; const &amp; v)
   { return v[I]; }
  
  template &lt;std::size_t I, typename T&gt;
  constexpr auto extrV (T const &amp; v)
   { return v; }
  
  template &lt;typename T, std::size_t N&gt;
  class Vec
   {
     private:
        std::array&lt;T, N&gt; d;
  
     public:
        template &lt;typename ... Ts&gt;
        Vec (Ts ... ts) : d{{ ts... }}
         { }
  
        T &amp; operator[] (int i)
         { return d[i]; }
  
        T const &amp; operator[] (int i) const
         { return d[i]; }
   };
  
  
  template &lt;std::size_t I, typename F, typename ... Args&gt;
  auto applyH2 (F &amp;&amp; f, Args ... as)
   { return f(extrV&lt;I&gt;(as)...); }
  
  template &lt;std::size_t ... Is, typename F, typename ... Args&gt;
  auto applyH1 (std::index_sequence&lt;Is...&gt; const &amp;, F &amp;&amp; f, Args ... as)
     -&gt; Vec&lt;decltype(applyH2&lt;0U&gt;(f, as...)), sizeof...(Is)&gt;
   { return { applyH2&lt;Is&gt;(f, as...)... }; }
  
  template &lt;typename F, typename ... Args, std::size_t N = dimVecV&lt;Args...&gt;&gt;
  auto apply (F &amp;&amp; f, Args ... as)
   { return applyH1(std::make_index_sequence&lt;N&gt;{}, f, as...); }
  
  long foo (int a, int b)
   { return a + b + 42; }
  
  int main ()
   {
     Vec&lt;int, 3U&gt;  v3;
     Vec&lt;int, 2U&gt;  v2;
  
     auto r1 { apply(foo, v2, v2) };
     auto r2 { apply(foo, v3, v3) };
     auto r3 { apply(foo, v3, 0)  };
  
     static_assert( std::is_same&lt;decltype(r1), Vec&lt;long, 2U&gt;&gt;{}, "!" );
     static_assert( std::is_same&lt;decltype(r2), Vec&lt;long, 3U&gt;&gt;{}, "!" );
     static_assert( std::is_same&lt;decltype(r3), Vec&lt;long, 3U&gt;&gt;{}, "!" );
  
     // apply(foo, v2, v3); // compilation error
     // apply(foo, 1, 2);   // compilation error
  
   }
  </code></pre>
  
  <p>now lets say I also have a template class <code>template &lt;typename T, size_t N, size_t M&gt; class mat;</code> which represents a <code>NxM</code> matrix with the previous <code>Vec</code>'s being equivalent to columns (<code>M</code>) for broadcasting, now I want to extend apply so it can also work with the <code>Mat</code> class with out breaking handling of just <code>vec</code>'s.</p>
  
  <p>Rules:</p>
  
  <ul>
  <li>if the argument list contains a <code>NxM</code> matrix then all matrices <code>NxM</code> and
  all vectors must be <code>M</code>, and the function will return a <code>NxM</code> matrix</li>
  <li>otherwise rules as previously for vectors, if the argument list
  contains a <code>N</code> vector then all vectors must be <code>N</code>, and the function will
  return a <code>N</code> vector</li>
  </ul>
  
  <p>As far as I can tell since the function <code>f()</code> isn't implemented for matrices then the <code>applyH2()</code> should fail (if not then it needs to), in its current form, thus apply would fail, hence it should be possible to implement another <code>apply()</code> which accepts multiple sizes <code>M</code> and <code>N</code> in the same way, which will be used if the argument list contains a matrix, and then invoke <code>extrV&lt;I,J&gt;(as)</code> which for vectors should be mapped as <code>extrV&lt;I,J&gt;(as) -&gt; extrV&lt;J&gt;(as)</code> this part seams pretty straight forward as dose implementing <code>dimMatM</code> and <code>dimMatN</code> in the same way as <code>dimVec</code> and such that <code>dimMatM</code> maps to <code>dimVec</code> for vectors.</p>
  
  <p>However I'm not sure how to go about getting the two versions on <code>apply()</code> to work together with out error.</p>
  
  <p>Optional: This part isn't really important by lets say that later I have a <code>class tensor&lt;T, N...&gt;</code> with extends the concept on vec and mat to N dimensions, would it be possible to extend apply to work such that broadcasting occurs over the leading dimensions i.e.</p>
  
  <pre><code>double f(float x, float y);
  int main() {
     tensor&lt;float, 2, 4, 6&gt; f246;
     tensor&lt;int, 4, 6&gt; i46;
     tensor&lt;float, 2, 4&gt; f24;
  
     auto r1 = apply(f, f246, i46); // returns tensor&lt;double, 2, 4, 6&gt;
     // apply(f, f24, f246); // Compile ERROR: dimensions don't match
  }
  </code></pre>
  
  <p>EDIT:</p>
  
  <p>I just thought up a possible solution or at least part of it see below</p>
  
  <pre><code>template &lt;size_t ...N&gt;
  struct tensor_helper {
  template &lt;size_t I, typename T, size_t ...M&gt; static tensorGet(const tensor&lt;T, M...&gt;&amp; V) { return V.v[I % product&lt;M...&gt;::value]; }
  template &lt;size_t I, typename T&gt; static tensorGet(const T&amp; V) { return V; }
  template &lt;std::size_t I, typename F, typename ...Args&gt;
  static auto applyH2 (F &amp;&amp; f, Args ...as) -&gt; decltype(f(std::declval&lt;typename base_type&lt;Args&gt;::type&gt;()...))
   { return f(tensorGet&lt;I&gt;(as)...); }
  template &lt;size_t ... Is, typename F, typename ... Args&gt;
  static auto applyH1(std::index_sequence&lt;Is...&gt; const &amp;..., F &amp;&amp; f, Args ... as) -&gt; tensor&lt;decltype(f(std::declval&lt;typename base_type&lt;Args&gt;::type&gt;()...)), N...&gt;
      { return make_tensor&lt;decltype(f(std::declval&lt;typename base_type&lt;Args&gt;::type&gt;()...)), N...&gt;({applyH2&lt;Is&gt;(f, as...)... }); }
  }
  
  template &lt;typename F, typename ...Args, size_t ...N = tensorSize&lt;Args...&gt; /* How do I get a list here? */&gt;
  auto apply (F &amp;&amp; f, Args ... as)
   { return tensor_helper&lt;N...&gt;::applyH1(std::make_index_sequence&lt;product&lt;N...&gt;&gt;{}..., f, as...); }
  </code></pre>
  
  <p>the only problem is how to get <code>tensorSize()</code> to provide a list of dims, all though I assume this could be manually expanded if just implemented for vectors and matrices, rather than using the parameter packs for dims.</p>
  
  <p>EDIT 2:
  I belive I can use <a href="https://stackoverflow.com/questions/27589563/create-a-variadic-template-from-a-constexpr-array">constexpr array to variadic template</a>, to solve the <code>N</code> list problem, from my above code. But I'm too tried too actualy try implementing that concept tonight will have a try tomorrow.</p>