7

I have my function overloaded in code below:

void function(char x, double y) {
    cout << "char, double" << endl;
}

void function(int x, int y) {
    cout << "int, int" << endl;
}

int main() {
    function('a', 'b');
    return 0;
}

When i try to compile it says me: "[Warning] ISO C++ says that these are ambiguous, even though the worst conversion for the first is better than the worst conversion for the second"

How does compiler make implicit conversions here so that it's ambiguous which candidate is right?

Clifford
  • 88,407
  • 13
  • 85
  • 165
Felix Vein
  • 119
  • 3

4 Answers4

10

The literal constants 'a' and 'b' have type char, so there is no exact match. The ambiguity occurs because the first parameter matched the first function, but the preferred conversion of the second is to int, matching the second function.

GCC is very explicit about this, issuing the following diagnostic:

warning: ISO C++ says that these are ambiguous, even though the worst conversion for the first is better than the worst conversion for the second

GCC seems to be saying, I could resolve this for you, but ISO C++ won't allow it. Type agreement is however important to good code quality and avoidance of errors.

You can coerce the selection by casting:

function( static_cast<int>('a'), static_cast<int>('b') );

or by supplying a function( char, char ) overload.

Clifford
  • 88,407
  • 13
  • 85
  • 165
  • @Jefffrey `C++11[conv.fpint]`. Note that `char` is an integer type. – Angew is no longer proud of SO Mar 11 '14 at 10:30
  • @Jefffrey: what Angew said. A `char` is an integer type, promotion and conversion rules apply. To answer your question, no I cannot tell you where in the standard it says that, the standard is fine for compiler writers and settling arguments of forums, but I tend to go with 25 years experience ;-) – Clifford Mar 11 '14 at 10:34
  • @Jeffrey `[conv]`: "Standard conversions are **implicit conversions** with built-in meaning ... A standard conversion sequence is a sequence of standard conversions in the following order: ... Zero or one conversion from the following set ... floating-integral conversions." (emph. mine) – Angew is no longer proud of SO Mar 11 '14 at 10:36
  • This doesn't explain why the overload resolution fails, however. The fact that `char` to `int` is a promotion, and not a conversion, is critical to the understanding here. – James Kanze Mar 11 '14 at 10:36
  • @JamesKanze: A char can be promoted to int and converted to double. Both assignments `double a = 'a'` and `double b = 10` are valid (by promotion and conversion respectively). Either way you can get from a char to either a double or an int - so it is ambiguous. – Clifford Mar 11 '14 at 10:40
  • 1
    @Clifford That's _not_ why it is ambiguous. It's ambiguous because for the first parameter, there is an exact match for the first function, so it is better, and because for the second parameter, the promotion `char` to `int` is "better" than the conversion `char` to `double`, so the second function is better. Without this distinction, the first function would be better for the first argument, both functions would be equal for the second, and the compiler would choose the first. – James Kanze Mar 11 '14 at 11:12
  • @JamesKanze: Ah! I see your point. I missed that the first parameter of the first was a `char`; you are right casting just the first parameter to `int` resolves the ambiguity. However you really should have posted your own answer perhaps? – Clifford Mar 11 '14 at 23:04
  • @Clifford I would have, but both Sebastian Redl and Angew basically covered the point before I'd seen the question. – James Kanze Mar 12 '14 at 14:18
  • @JamesKanze: Then I am embarrassed that this so far has higher upvotes! I think I've fixed it, but only by stealing your input. – Clifford Mar 12 '14 at 20:17
4

There are implicit conversions between double, int, and char in C++, so you should use static_cast<int> to convert data from char to int for example.

function( static_cast<int>(c), static_cast<int>(d) );

this will call function( int, int );

In your particular case, you use 'a' and 'b' character literals, which, as I mentioned above, have implicit conversions to int and double, because a char variable represents the ASCII value of the character entered in the assignment operator. Hence, we can initialize an unsigned char variable, or a char in the ways below:

unsigned char a = 97; // the ASCII decimal code for "a"
unsigned char b = 'a'; // translates into 97

Since an unsigned char or char variables is an 8 bits variable, and int is a 32 bit value, they have implicit conversions.

Victor
  • 13,914
  • 19
  • 78
  • 147
2

For overload A to be chosen over overload B, the conversions for each argument to A must be as good or better than those for B, and at least one must be better.

In your case, A has (exact match, integral->floating), whereas B has (integral promotion, integral promotion).

Exact match is better than integral promotion, but integral promotion is better than integral->floating conversion. So A has a better conversion in the first argument, and B in the second. So it's ambiguous which one is better overall.

Sebastian Redl
  • 69,373
  • 8
  • 123
  • 157
1

Trying ('a', 'b') for function(char, double) requires no conversion for 'a', and a floating-integral conversion for 'b' (from char to double).

For function(int, int), both 'a' and 'b' require integral promotion (from char to int).

Angew is no longer proud of SO
  • 167,307
  • 17
  • 350
  • 455
  • And of course, integral promotion is a better match than floating-integral. (It's sort of implicit in what you write, but it's worth pointing out.) – James Kanze Mar 11 '14 at 10:34