title: Detecting parameter types from generic lambda - compile error with GCC
body: <p>I wrote some code that retrieves the types of the non-auto parameters when given a generic lambda function. As you can see in the code below, the idea is to call the connect function with a generic lambda and provide arguments for the auto parameters (which will always be at the front in my use case). So in the code below my goal was to detect that the second parameter is of type float.</p>
  
  <p>The code works fine with clang 3.8 but it doesn't compile with gcc 6.1.1, so I was wondering whether this was a bug in gcc or if this is just not valid c++ code? Can I assume that a generic lambda is implemented with a templated operator() function or is this compiler-specific?</p>
  
  <pre><code>template &lt;typename Functor, typename... AllArgs, typename... ProvidedArgs&gt;
  void findArgTypes(void(Functor::*)(AllArgs...) const, Functor, ProvidedArgs...)
  {
      // AllArgs == int, float
      // ProvidedArgs == int
  }
  
  template &lt;typename Func, typename... ProvidedArgs&gt;
  void connect(Func func, ProvidedArgs... providedArgs)
  {
      findArgTypes(&amp;Func::template operator()&lt;ProvidedArgs...&gt;, func, providedArgs...);
  }
  
  int main()
  {
      int tmp = 0;
      connect([&amp;](auto, float){ ++tmp; }, 0);
  }
  </code></pre>
  
  <p>The error that gcc gives is this:</p>
  
  <pre><code>main.cpp: In instantiation of ‘void connect(Func, ProvidedArgs ...) [with Func = main()::&lt;lambda(auto:1, float)&gt;; ProvidedArgs = {int}]’:
  main.cpp:16:33:   required from here
  main.cpp:11:17: error: no matches converting function ‘operator()’ to type ‘void (struct main()::&lt;lambda(auto:1, float)&gt;::*)() const’
       findArgTypes(&amp;Func::template operator()&lt;ProvidedArgs...&gt;, func, providedArgs...);
       ~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  main.cpp:16:27: note: candidate is: template&lt;class auto:1&gt; main()::&lt;lambda(auto:1, float)&gt;
       connect([](auto, float){}, 0);
                             ^
  </code></pre>
  
  <p>Removing the <code>const</code> in findArgTypes gives the same result.</p>
  
  <p>Using the following code works with both compilers:</p>
  
  <pre><code>struct Foo
  {
      template &lt;typename T&gt;
      void operator()(T, float) const {}
  };
  
  int main()
  {
      Foo f;
      connect(f, 0);
  }
  </code></pre>