Reputation: 357
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
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