title: Parameter Pack Matching Rules with Multiple Packs
body: <p>I am trying to write a function which takes another function, using parameter packs and some standard matching rules. As an example:</p>
  
  <pre><code>template &lt;typename... TListElems, typename... TVectorElems&gt;
  void goal(void (*fn)(std::list&lt;TListElems&gt;..., std::vector&lt;TVectorElems&gt;...));
  </code></pre>
  
  <p>In order to disambiguate <code>TListElems</code> and <code>TVectorElems</code>, I added some <code>std::tuple&lt;T...&gt;*</code> so a caller can be explicit:</p>
  
  <pre><code>template &lt;typename... TListElems, typename... TVectorElems&gt;
  void foo(std::tuple&lt;TListElems...&gt;*,
           std::tuple&lt;TVectorElems...&gt;*,
           void (*)(std::list&lt;TListElems&gt;..., std::vector&lt;TVectorElems&gt;...))
  {
      // blah blah blah
  }
  
  void bar(std::list&lt;int&gt;, std::list&lt;unsigned&gt;, std::vector&lt;float&gt;, std::vector&lt;double&gt;)
  {
      // blah blah blah
  }
  
  int main()
  {
      foo((std::tuple&lt;int, unsigned&gt;*) nullptr,
          (std::tuple&lt;float, double&gt;*) nullptr,
          &amp;bar);
  }
  </code></pre>
  
  <p>Clang happily compiles this in the way I would expect, while g++ (7.2.1) gives the compilation error:</p>
  
  <pre><code>matching.cpp: In function ‘int main()’:
  matching.cpp:20:13: error: no matching function for call to ‘foo(std::tuple&lt;int, unsigned int&gt;*, std::tuple&lt;float, double&gt;*, void (*)(std::list&lt;int&gt;, std::list&lt;unsigned int&gt;, std::vector&lt;float&gt;, std::vector&lt;double&gt;))’
           &amp;bar);
               ^
  matching.cpp:6:6: note: candidate: template&lt;class ... TListElems, class ... TVectorElems&gt; void foo(std::tuple&lt;_Tps ...&gt;*, std::tuple&lt;_Elements ...&gt;*, void (*)(std::list&lt;TListElems&gt;..., std::vector&lt;TVectorElems&gt;...))
   void foo(std::tuple&lt;TListElems...&gt;*,
        ^~~
  matching.cpp:6:6: note:   template argument deduction/substitution failed:
  matching.cpp:20:13: note:   mismatched types ‘std::vector&lt;TVectorElems&gt;’ and ‘std::list&lt;int&gt;’
           &amp;bar);
               ^
  </code></pre>
  
  <p>In <code>main</code>, I would <em>expect</em> the call to <code>foo</code> to deduce <code>TListElems</code> as <code>&lt;int, unsigned&gt;</code> and <code>TVectorElems</code> as <code>&lt;float, double&gt;</code>, leading <code>fn</code> to be of type <code>void (*)(std::list&lt;int&gt;, std::list&lt;unsigned&gt;, std::vector&lt;float&gt;, std::vector&lt;double&gt;)</code> (the way things operate when there is only one pack or if I had manually written the overload).</p>
  
  <p>§14.8.2.5/10 is the closest the Standard comes to explicitly preventing the <code>foo</code> example from working:</p>
  
  <blockquote>
    <p>[Note: A function parameter pack can only occur at the end of a parameter-declaration-list (8.3.5). -end note]</p>
  </blockquote>
  
  <p>The <code>std::list&lt;TListElems&gt;...</code> bit of <code>fn</code> seems like it would violate this note, but that's not entirely clear.</p>
  
  <p>The question is: Who is right? GCC, Clang, or something else?</p>