omicronns
omicronns

Reputation: 357

Template function ambiguous parameter deduction for 0

I have a strange issue while compiling following example.

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

template<typename T>
void foo(typename identity<T>::type v) {}

template<typename T>
void foo(typename identity<T>::type* v) {}

int main() {
    foo<int>(0);
    foo<short>(0);
    return 0;
}

Calling foo<int>(0) compiles, but, when I call foo<short>(0), compiler can't deduce if 0 is a value or a pointer. I use identity to force explicit specification of template parameter. Compiler(msvc) error message:

error C2668: 'foo': ambiguous call to overloaded function

Is it compiler bug?

Upvotes: 3

Views: 128

Answers (1)

Bathsheba
Bathsheba

Reputation: 234875

It is not a compiler bug. This is due to the fact that converting 0 to a pointer type has "Conversion rank".

C++11 §4.10 (Conversion rank)

A null pointer constant is an integer literal (2.13.2) with value zero or a prvalue of type std::nullptr_t. A null pointer constant can be converted to a pointer type; the result is the null pointer value of that type and is distinguishable from every other value of object pointer or function pointer type. Such a conversion is called a null pointer conversion.

So when you write a 0 literal, and a conversion is necessary, the compiler encounters two overloads of similar rank - one a non-pointer type, and the other a pointer type.

Some more examples:

 foo<short>((short)0); // No conversion necessary: allowed
 foo<nullptr_t>(nullptr); // No conversion necessary: allowed
 foo<nullptr_t>(0); // ambiguous
 foo<nullptr_t>(NULL); // ambigious - another reason to stop using NULL

Upvotes: 3

Related Questions