Several examples about template partial ordering to which GCC and Clang disagree

Viewed 90

The first example is

template <class... T> struct V {}; 
template <class... Ts, class... Us> void Foo(V<Ts...>, V<Us&...>) {} // #3 
template <class... Us> void Foo(V<>, V<Us&...>) {}                   // #4 
void h() { 
   Foo(V<>(), V<>()); 
} 

The above example is mentioned in CWG2235. In that paper, which says #4 is a better candidate. However, GCC and Clang have disagreements with this example. I think GCC is correct, my reason is, Take #4 as argument template and #3 as parameter template, the deductions are successful for each pair that is used to determine the ordering.
Instead, when take #3 as argument template and #4 as parameter template, the following rules is applied here
temp.deduct.type#9

During partial ordering, if Ai was originally a pack expansion:

  • if P does not contain a template argument corresponding to Ai then Ai is ignored;
  • otherwise, if Pi is not a pack expansion, template argument deduction fails.

That means the deduction is still successful for each pair. Finally, there's no special rule in section [temp.deduct.partial] to determine which is more specialized. Hence, it should be ambiguous here which should be GCC's opinion.

For this example, if I have some misunderstanding, please point it out.


Now, consider a bit complex example that GCC and Clang also disagree.

#include <iostream>
struct A { };
template<class T> 
struct B {
    template<class R> 
    int operator*(R) {
        std::cout<<"#1\n";
        return 0;  
    }
};

template<class R> 
int operator*(B<A>&&, R){
  std::cout<<"#2\n";
  return 0;
}
int main(){
    B<A>{} * 0;
}

GCC considers the example as ambiguous while Clang chooses #1. This time, I'm still a proponent of GCC. My reason is
temp.func.order#3

For a function template M with cv-qualifiers cv that is a member of a class A:

  • The type X(M) is “rvalue reference to cv A” if the optional ref-qualifier of M is && or if M has no ref-qualifier and the positionally-corresponding parameter of the other transformed template has rvalue reference type; if this determination depends recursively upon whether X(M) is an rvalue reference type, it is not considered to have rvalue reference type.

It means that the implicit parameter of #1 should be B<A>&& during the ordering partial. Which is identical with the first parameter in #2 and the other pair can also be deduced successfully in both directions. Hence, #1 and #2 should be ambiguous here too.

In general, in these two examples, I agree with the result processed by GCC. If I misunderstand something, please point it out.

0 Answers
Related