This seems inconsistent. I have 3 functions f
overloaded for signed types short
, int
and long long
. If you pass an unsigned short
then it gets promoted to the next biggest signed type int
. However if you pass unsigned int
then it doesn't get promoted to signed long long
which is what I would expect, rather compiler complains about ambiguous call to overloaded function.
void f(short x) { std::printf("f(short)\n"); }
void f(int x) { std::printf("f(int)\n"); }
void f(long long x) { std::printf("f(long long)\n"); }
int main()
{
f((unsigned short)0); // Fine: calls f(int)
// f((unsigned int)0); // Ambiguous: could be f(short), f(int) or f(long long)
}
In Function overloading, sometimes a situation can occur when the compiler is unable to choose between two correctly overloaded functions. This situation is said to be ambiguous. Ambiguous statements are error-generating statements and the programs containing ambiguity will not compile.
prog.cpp:25:11: error: call of overloaded ‘test (char)’ is ambiguous When there is no exact type match, the compiler looks for the closest match. The closest match for “test (‘a’);” will be “void test (int a)”, since it is not present, void test (double d) and void (float f)will cause ambiguity.
If you pass an unsigned short then it gets promoted to the next biggest signed type int. However if you pass unsigned int then it doesn't get promoted to signed long long which is what I would expect, rather compiler complains about ambiguous call to overloaded function.
Here, in the unambiguous call statement test (10, 11) two arguments are specified, therefore there is no ambiguity. In the ambiguous call statement test (10), the compiler gets confused about whether to call the first function test () which takes one argument or to call the second test () function with two arguments out of which one is the default.
It is inconsistent, yes, but it is The Way The Language Is, and you have to cope, e.g. if you want f((unsigned int)0)
to call the long long
overload, then provide a wrapper,
inline void f(unsigned int x) { f((long long)x); }
The designers of C++ would have ideally liked to make both of your cases fail overload resolution. But there was this legacy thing (dating all the way back to "K&R" C), called "default argument promotion", that, essentially, says the compiler will implicitly convert all integer types narrower than int
to int
if necessary to match a function signature, and all floating point types narrower than double
to double
ditto.
So it's the f((unsigned short)0)
case that is the odd man out, really.
http://en.cppreference.com/w/cpp/language/implicit_conversion
Integral promotion does not get you from unsigned int
to long long
.
Integral promotion does get you from unsigned short
to int
.
Integral conversion from unsigned int
is considered equally good for your overloads.
Promotion ends at int
and/or unsigned int
unless your source type is an enum
that requires a larger integral type to fit it.
Promotion is preferred to conversion, so your first case is unambiguous. In the second case, there is no promotion path, so your code is ambiguous.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With