#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).