title: Generic lambdas, overloading, std::is_invocable and SFINAE - different behavior among GCC and Clang
body: <h3>Problem</h3>
  
  <p>I wrote a convoluted piece of template code that can be compiled <a href="https://wandbox.org/permlink/KlxvED1Qt5dXWJL6" rel="nofollow noreferrer">with GCC 8.2.1</a>, but not <a href="https://wandbox.org/permlink/FufiSx2clKKdvU0i" rel="nofollow noreferrer">with Clang 7.0</a> (code and error links).</p>
  
  <p>I think this might be an implication of <a href="https://stackoverflow.com/questions/12015938/overload-resolution-behaviour-difference-between-gcc-and-clang-sfinae">this Q&amp;A</a>, but I am unable to see it.</p>
  
  <h3>Motivation</h3>
  
  <p>I am writing a class, which I would like to be constructible with two callables of different types, but also with one of them omitted, i.e.:</p>
  
  <pre><code>my_class(callable_1);
  my_class(callable_2);
  my_class(callable_1, callable_2);
  </code></pre>
  
  <p>That should go without problems. But, why not allow <code>callable_1</code> and <code>callable_2</code> to be function templates (or functors with <code>operator()</code> template). That is, I would like to have this (or at least initially wanted):</p>
  
  <pre><code>my_class([](auto arg) {});
  my_class([](auto arg) {});
  my_class([](auto arg) {}, [](auto arg) {});
  </code></pre>
  
  <p>As, you can see, both callables unfortunately have the same signature, so we need to disambiguate between them somehow. The first approach I could think of (and the one this question is about) is to add a "tag" parameter to one of the unary overloads:</p>
  
  <pre><code>my_class([](auto arg) {});
  my_class([](auto arg) {}, callable_2_tag());
  my_class([](auto arg) {}, [](auto arg) {});
  </code></pre>
  
  <p>This, to me, looks acceptable, but I have come up with better solutions:</p>
  
  <ul>
  <li>use the tag (optional if not ambiguous) in the second callable's signature (the last parameter or return type)</li>
  <li>make the second constructor overload into a differently named non-member or <code>static</code> member function</li>
  </ul>
  
  <p><strong>Still, I would like to know, why there is the difference in behavior among the two compilers with my initial approach and which one is correct</strong> (or whether both are).</p>
  
  <hr>
  
  <h3>Code:</h3>
  
  <p>I have translated the constructor overloads into regular <code>my_class</code> function overloads for simplicity.</p>
  
  <pre><code>#include &lt;iostream&gt;
  #include &lt;type_traits&gt;
  
  // parameter types for callbacks and the tag class
  struct foo { void func1() {} };
  struct bar { void func2() {} };
  struct bar_tag {};
  
  // callable checks
  template &lt;typename Func&gt;
  static constexpr bool is_valid_func_1_v = std::is_invocable_r_v&lt;void, Func, foo&gt;;
  
  template &lt;typename Func&gt;
  static constexpr bool is_valid_func_2_v = std::is_invocable_r_v&lt;void, Func, bar&gt;;
  
  // default values
  static constexpr auto default_func_1 = [](foo) {};
  static constexpr auto default_func_2 = [](bar) {};
  
  // accepting callable 1
  template &lt;typename Func1, std::enable_if_t&lt;is_valid_func_1_v&lt;Func1&gt;&gt;* = nullptr&gt;
  void my_class(Func1&amp;&amp; func_1)
  {
      my_class(std::forward&lt;Func1&gt;(func_1), default_func_2);
  }
  
  // accepting callable 1
  template &lt;typename Func2, std::enable_if_t&lt;is_valid_func_2_v&lt;Func2&gt;&gt;* = nullptr&gt;
  void my_class(Func2&amp;&amp; func_2, bar_tag)
  {
      my_class(default_func_1, std::forward&lt;Func2&gt;(func_2));
  }
  
  // accepting both
  template &lt;
      typename Func1, typename Func2,
      // disallow Func2 to be deduced as bar_tag
      // (not even sure why this check did not work in conjunction with others,
      // even with GCC)
      std::enable_if_t&lt;!std::is_same_v&lt;Func2, bar_tag&gt;&gt;* = nullptr,
      std::enable_if_t&lt;is_valid_func_1_v&lt;Func1&gt; &amp;&amp;
                       is_valid_func_2_v&lt;Func2&gt;&gt;* = nullptr&gt;
  void my_class(Func1&amp;&amp; func_1, Func2&amp;&amp; func_2)
  {
      std::forward&lt;Func1&gt;(func_1)(foo());
      std::forward&lt;Func2&gt;(func_2)(bar());
  }
  
  int main()
  {
      my_class([](auto foo) { foo.func1(); });
      my_class([](auto bar) { bar.func2(); }, bar_tag());
  }
  </code></pre>
  
  <p>For Clang, this will result in:</p>
  
  <pre><code>error: no member named 'func1' in 'bar'
  my_class([](auto foo) { foo.func1(); });
                          ~~~ ^
  ...
  note: in instantiation of variable template specialization
  'is_valid_func_2_v&lt;(lambda at prog.cc:41:14)&gt;' requested here
  template &lt;typename Func2, std::enable_if_t&lt;is_valid_func_2_v&lt;Func2&gt;&gt;* = nullptr&gt;
                                             ^
  </code></pre>
  
  <p>What happened here? <strong>Substitution failure is an error?</strong></p>
  
  <p><strong>Edit:</strong> It was completely ignorant from me to think that an error inside a predicate of <code>std::enable_if</code> will be silenced as well... That is <strong>not</strong> a substitution failure.</p>
  
  <h3>Fix:</h3>
  
  <p>If I put the SFINAE as a function parameter, Clang handles it well. <strong>I do not know why deferring the check from the template argument deduction stage to the overload resolution stage makes the difference.</strong></p>
  
  <pre><code>template &lt;typename Func2&gt;
  void my_class(Func2&amp;&amp; func_2, bar_tag,
                std::enable_if_t&lt;is_valid_func_2_v&lt;Func2&gt;&gt;* = nullptr)
  {
      my_class(default_func_1, std::forward&lt;Func2&gt;(func_2));
  }
  </code></pre>
  
  <hr>
  
  <p>All in all, I have dived into genericity probably more than I should have with my knowledge and now I am paying for it. So what is it that I am missing? Attentive reader might notice some side questions popping up, but I do not want an answer for all of them. Lastly, I am sorry if a much simpler MCVE could have been made.</p>