32

I'm reading the standard and trying to figure out why this code won't be resolved without a cast.

void foo(char c) { }

// Way bigger than char
void foo(unsigned long int) { }

int main()
{
   foo(123456789); // ambiguous
   foo((unsigned long int) 123456789); // works
}

Here's what it says:

4.13 Integer conversion rank [conv.rank]

Every integer type has an integer conversion rank defined as follows:

— The rank of any unsigned integer type shall equal the rank of the corresponding signed integer type.

— The rank of char shall equal the rank of signed char and unsigned char.

In particular, what rustles my jimmies is that it doesn't say ANY unsigned integral type, just unsigned char. My guess is that char is being promoted to an unsigned type via conversion. Is this true?

Pete Becker
  • 69,019
  • 6
  • 64
  • 147
user4073503
  • 319
  • 2
  • 4
  • 3
    Perhaps 123456789U would do it for you. – WhozCraig Sep 24 '14 at 07:30
  • "In particular, what rustles my jimmies is that it doesn't say ANY unsigned integral type, just unsigned char. My guess is that char is being promoted to an unsigned type via conversion. Is this true?" - I'd hazard that you're misunderstanding the significance of 4.13 in the Standard... `char` is not being promoted to `unsigned`... the issue is as AndreyT says - that 123456789 is an `int` and it's not clearly better to truncate it as a `char` or pass it as an `unsigned long` (`long` would be just as bad - `unsigned` is not significant here). – Tony Delroy Sep 24 '14 at 07:37
  • 1
    Despite the name, the "integer conversion rank" isn't actually used to rank integer conversions during overload resolution. – T.C. Sep 24 '14 at 09:08
  • 5
    Neither conversion is safe -- one is signed to unsigned and the other is larger type to smaller type -- so why should one unsafe operation win over the other? – David Schwartz Sep 24 '14 at 09:38
  • +1 For "rustles my jimmies" – skrrgwasme Sep 24 '14 at 22:44
  • "it doesn't say ANY unsigned integral type, just unsigned char" - what part are you referring to? In what you quoted I don't see anything that would give any exclusive treatment to `unsigned char`. – AnT Sep 25 '14 at 14:21

1 Answers1

52

It has little to do with rank of the type defined in 4.13. 4.13 defined internal rankings used to describe integral promotions and usual arithmetic conversions. They by itself do not directly affect overload resolution. Rankings relevant to overload resolution are defined in "13.3.3.1.1 Standard conversion sequences" and then used in "13.3.3.2 Ranking implicit conversion sequences".

So, it is about rank of the conversion as defined under 13.3. 123456789 is an integer literal of type int on your platform. This means that calling both char and unsigned long versions of your function requires an implicit conversion from int to char or from int to unsigned long. In both cases we have conversions of "integral conversion" type. That means that both functions are equally "bad" in this case. Hence the ambiguity.

If one of these functions required a mere integral promotion (as opposed to integral conversion), it would win the resolution and the call would be considered unambiguous. But alas both of your functions require integral conversions.

AnT
  • 291,388
  • 39
  • 487
  • 734
  • 1
    Or, another way of looking at it: the function call overload doesn't distinguish between `123456789` and `-123456789`, both are `int`s. Converting `-123456789` to `unsigned long` could lose data: so in general, a conversion from `int` to `unsigned long` could lose data. The same is true of `char`. Now, with the specific constant of `123456789` you can prove that it won't be lost, but the overload rules do not take that into account: the type of `123456789` is `int` on your system, so `int` is used to do overload resolution. – Yakk - Adam Nevraumont Sep 24 '14 at 17:46