Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ ambiguous call to overloaded function with unsigned int

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) 
}
like image 293
George Skelton Avatar asked Oct 26 '16 18:10

George Skelton


People also ask

What is ambiguity in C++ function overloading?

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.

What is the error call of overloaded Char is ambiguous?

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.

What happens if you pass an unsigned int to a function?

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.

What is the difference between ambiguous call statement test 10 and 11?

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.


2 Answers

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.

like image 58
zwol Avatar answered Oct 10 '22 13:10

zwol


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.

like image 43
Yakk - Adam Nevraumont Avatar answered Oct 10 '22 13:10

Yakk - Adam Nevraumont