Home > OS >  Ambiguity in Function Overloading Rules? (Exact > Promote > Convert)
Ambiguity in Function Overloading Rules? (Exact > Promote > Convert)

Time:04-14

#include <string>
void foo(int x, short y, int z) { std::cout << "normal int" << std::endl; } //F1
void foo(double x, int y, double z) { std::cout << "normal double" << std::endl; } //F2

int main()
{
    short x = 2;
    foo(5.0, x, 8.0);
}

Based on function overloading rules, F1( Exact = 1, Promote = 0, Convert = 2 ) and F2( Exact = 2, Promote = 1, Convert = 0 ). Shouldn't F2 be called? Why is the call ambiguous?

CodePudding user response:

Overload resolution can get complicated. But here it's fairly straightforward. I'll rewrite the function prototypes to remove the third argument, since it doesn't affect the analysis.

void foo(int, short);
void foo(double, int);

double d = 1.0;
short s = 2;

f(d, s); // ambiguous

The rule is that you look at each argument, one at a time, and determine which function has the "best" conversion for that argument. If one function has the best conversion for every argument, that's the one that's called. If there's no function that's best for every argument, the call is ambiguous.

For the first argument, the type of the argument is double. Calling the first version of foo requires a conversion from double to int; calling the second version of foo requires no conversion; it's an exact match. So for the first argument, the second version of foo has the best conversion.

For the second argument, the type of the argument is short. Calling the first version of foo requires no conversion; it's an exact match. Calling the second version of foo requires a promotion from short to int. So for the second argument, the first version of foo has the best conversion.

Since the first version of foo has the best match for the second argument and the second version of foo has the best match for the first argument, there is no function with the best match on all arguments, and the call is ambiguous.

CodePudding user response:

Overload resolution ranks the viable candidate functions by comparing how each argument of the call matches the corresponding parameter of the candidates. Moreover, for one candidate to be considered better than another, the better candidate cannot have any of its parameters be a worse match than the corresponding parameter in the other candidate.

Now, let's apply this to your given example.

void foo(int x, short y, int z);
void foo(double x, int y, double z) ;
int main()
{
    short x = 2;
    foo(5.0, x, 8.0);
}

In the above snippet, For the case of first overloaded foo, the second argument matches exactly the type of the second parameter. But the first and third argument have type double while the corresponding parameters have type int and so the first and the third argument requires a conversion to int in this case.

On the other hand, for the case of second overloaded foo, the first and third argument matches exactly with the first and third parameter respectively. But in this case, the second argument is of type short while the second parameter is of type int. So a promotion to int is needed for the second argument.


Result 1

Now, according to the highlighted part at the beginning of my answer, for the first candidate to be considered a better match than the second candidate, none of the first candidate's parameter can be a worse match than the corresponding parameter in the second candidate. But we already discussed that the first and third parameter of first overloaded candidate are worse match that the corresponding parameters in the second overloaded candidate since they require conversion to int. Thus, the first overloaded candidate is not a better match than the second overloaded candidate.


Result 2

Similarly, for the second candidate to be considered a better match than the first candidate, none of the second candidate's parameter can be a worse match than the corresponding parameter in the first candidate. But here also we already discussed that the second parameter in the second candidate is worse match than the corresponding parameter in the first candidate since it requires a promotion. Thus, the second candidate is not a better match than the first candidate.


Conclusion

Combining both of the results above, we get to the conclusion that none of the candidates is better than the other. Hence the call is ambiguous.

CodePudding user response:

The ranking of conversion sequences matters only when comparing ranking of the conversion sequences applied to the same argument.

If one argument's conversion rank is better in the first overload than in the second one and the other way around for another argument's conversion rank, then neither overload is considered better than the other and the overload resolution is ambiguous.

This applies here. The first and third argument have a better conversion rank (exact rather than conversion) in the second overload, while the second argument has a better conversion rank in the first overload (exact rather than promotion).

  • Related