Barry
Barry

Reputation: 302757

Ambiguous call for overloaded function templates - even if one is more specialized?

Consider the following:

#include <utility>

template <int N>
using size_ = std::integral_constant<int, N>; 

template <int From>
void f(size_<From>, size_<From+1> ) // (1)
{ }

template <int From, int To>   // (2)
void f(size_<From>, size_<To> )
{ }

int main()
{
    f(size_<0>{}, size_<1>{});
}

Both gcc and clang report the call as ambiguous. Why? Isn't (1) more specialized than (2)?

Note: I know this is easily fixable with an extra enable_if_t<(To > From+1)> thrown into (2), but I wouldn't have thought I needed to do that.

Upvotes: 10

Views: 403

Answers (1)

Columbo
Columbo

Reputation: 60979

This was - unsurprisingly - addressed by a similar example in a CWG issue, namely #455:

In case that one of the arguments is non-deuced then partial ordering should only consider the type from the specialization:

template<typename T> struct B { typedef T type; };

template<typename T> char* f3(T, T);                   // #7
template<typename T> long* f3(T, typename B<T>::type); // #8

char* p3 = f3(p3, p3); // #9

According to my reasoning #9 should yield ambiguity since second pair is (T, long*). The second type (i.e. long*) was taken from the specialization candidate of #8. EDG and GCC accepted the code. VC and BCC found an ambiguity.

Both ICC and VC++ compile your code. According to current wording, they are correct: Each pair is handled independently, and as size_<From+1> makes From appear in a non-deduced context ([temp.deduct.type]/(5.3)), deduction necessarily fails, and hence size_<From+1> is at least as specialized as size_<To> but not vice versa. Thus overload (1) is more specialized than (2).

So ICC and VC++ (presumably) process every deduction pair and conclude that, for the second one, size_<To> is not at least as specialized as size_<From+1>.
Clang and GCC (presumably) argue that, for (1), From is deduced from the first argument, and thus need not be deduced in the second pair for size_<To> to be at leas as specialized as its counterpart.

Upvotes: 3

Related Questions