6

I'm trying to figure out how implicit conversion works.
I have 3 functions

Foo(int, int)
Foo(short, short)
Foo(short, unsigned char)

Then I call

Foo(unsigned char, unsigned char)

and Foo(int, int) is called. Can somebody explain how it works?

alain
  • 11,939
  • 2
  • 31
  • 51
Livace
  • 126
  • 7
  • 5
    There should be ample explanation [here](https://stackoverflow.com/questions/388242/the-definitive-c-book-guide-and-list). Depends on what angle you are actually asking about. "how it works" is kinda broad. – StoryTeller - Unslander Monica Dec 25 '17 at 11:47
  • 1
    And there's also the problem of this in fact [being ambiguous](http://coliru.stacked-crooked.com/a/073f1c74bd29e280). What compiler are you using? – StoryTeller - Unslander Monica Dec 25 '17 at 11:52
  • 2
    GCC seems to compile with a warning https://godbolt.org/g/PjjDwY. – DeiDei Dec 25 '17 at 11:53
  • I've actually got the same warnings too. But MinGW compiled it, so I'm now interested how it works inside. – Livace Dec 25 '17 at 11:55
  • 3
    @DeiDei - GCC "fixes" it as an extension (read the warning text). It's not a portable call. – StoryTeller - Unslander Monica Dec 25 '17 at 11:55
  • Check these pages http://en.cppreference.com/w/cpp/language/overload_resolution and http://en.cppreference.com/w/cpp/language/implicit_conversion, you'll find plenty of information regarding overload resolution and ranking of implicit conversion sequences. – Holt Dec 25 '17 at 12:11

1 Answers1

10

TL;DR; This is ill-formed according to the standard, which is why you get warnings/errors when compiling with gcc/clang. There is an ambiguity between the first and the third call because the implicit conversion sequence from unsigned char to short is worse than the one from unsigned char to int (first one is a conversion while the second one is a promotion).


You have to consider 3 different implicit conversion sequences in this example, each one containing a single standard conversion:

  • unsigned char to unsigned char, which is an exact match.
  • unsigned char to short which is an integral conversion.
  • unsigned char to int which is an integral promotion.

The ranking of the conversion sequences is a follows:

exact match > integral promotion > integral conversion

For an overload FooA to be better than an overload FooB, implicit conversions for all arguments of FooA have to be not worse than implicit conversions for arguments of FooB, and at least one of the implicit conversion for FooA must be better than the corresponding conversion for FooB.

In your case:

  • Foo(int, int) vs. Foo(short, short) — First one is better because unsigned char to int (promotion) is better than unsigned char to short (conversion).
  • Foo(int, int) vs. Foo(short, unsigned char) — This is ambiguous:
    • unsigned char to int is better than unsigned char to short.
    • unsigned char to int is worse than unsigned char to unsigned char.
  • Foo(short, short) vs. Foo(short, unsigned char) — Second one is better because unsigned char to unsigned char (exact match) is better than unsigned char to short (conversion).

There is an ambiguity only between Foo(int, int) and Foo(short, unsigned char), the second overload Foo(short, short) does not participate in the "ambiguity". If you remove either the first or the third overload, the ambiguity disappears and the first or the third overload is chosen.

Holt
  • 36,600
  • 7
  • 92
  • 139
  • Thanks! This makes it more clearly. But why is `uchar -> int` promotion and `uchar -> short` conversion? – Livace Dec 25 '17 at 12:21
  • @Livace Because the standard says so. ^^' I guess it's because you don't want to have multiple promotions from a type to avoid weird rankings in some case, but I am not enough expert to give you a concrete example. – Holt Dec 25 '17 at 12:31
  • Re: "This should not compile..." -- note that the language definition does not impose that constraint. The only requirement is that the compiler must **issue a diagnostic**; having done that, the compiler is free to do whatever the implementor wants, including producing code that does something that the implementor believes is sensible. – Pete Becker Dec 25 '17 at 13:57
  • @PeteBecker You're right, I've changed the phrasing using *ill-formed* which is, I think, correct here. – Holt Dec 25 '17 at 14:05