'Ambiguous overload error when using conversion function
I am trying to understand overloading resolution in C++ through the books listed here. One such example that i wrote to clear my concepts whose output i am unable to understand is given below.
#include <iostream>
struct Name
{
operator int()
{
std::cout<<"Name's int version called"<<std::endl;
return 4;
}
operator float()
{
std::cout<<"Name's float version called"<<std::endl;
return 1.1f;
}
};
int main()
{
double a = Name(); //this works and calls Name's float version. But WHY ISN'T THIS AMBIGIOUS?
long double b = Name(); //this does not work. WHY IS THIS AMBIGIOUS?
bool c = Name(); //this does not work. WHY IS THIS AMBIGIOUS?
return 0;
}
As you can see here the program works when creating double a
. But when i try to create objects b
and c
it gives error.
My questions are:
Why don't we get the ambiguity error for object
a
. That is, among the two conversion operators in className
, why thefloat
version is chosen over theint
version.Why/how do we get the ambiguity error for object
b
which is along double
. That is just like fora
, i suspected that thefloat
version should have been called but instead we get the error. How is this different from thedouble a
case above.Why/how do we get the ambiguity error for object
c
which isbool
. In this case, I suspected that theint
version could have been chosen but instead we get an error. How is this different than thedouble a
version which works and usesfloat
version of conversion function.
I just want to understand why/how the first version works but the other two don't.
Solution 1:[1]
Essentially, skipping over some stuff not relevant in this case, overload resolution is done to choose the user-defined conversion function to initialize the variable and (because there are no other differences between the conversion operators) the best viable one is chosen based on the rank of the standard conversion sequence required to convert the return value of to the variable's type.
The conversion int -> double
is a floating-integral conversion, which has rank conversion.
The conversion float -> double
is a floating-point promotion, which has rank promotion.
The rank promotion is better than the rank conversion, and so overload resolution will choose operator float
as the best viable overload.
The conversion int -> long double
is also a floating-integral conversion.
The conversion float -> long double
is not a floating-point promotion (which only applies for conversion float -> double
). It is instead a floating-point conversion which has rank conversion.
Both sequences now have the same standard conversion sequence rank and also none of the tie-breakers (which I won't go through) applies, so overload resolution is ambigious.
The conversion int -> bool
is a boolean conversion which has rank conversion.
The conversion float -> bool
is also a boolean conversion.
Therefore the same situation as above arises.
See https://en.cppreference.com/w/cpp/language/overload_resolution#Ranking_of_implicit_conversion_sequences and https://en.cppreference.com/w/cpp/language/implicit_conversion for a full list of the conversion categories and ranks.
Although it might seem that a conversion between floating-point types should be considered "better" than a conversion from integral to floating-point type, this is generally not the case.
Solution 2:[2]
In this initialization
double a = Name();
there is used the floating point promotion.
The C++ 17 Standard (7.7 Floating-point promotion)
1 A prvalue of type float can be converted to a prvalue of type double. The value is unchanged. 2 This conversion is called floating-point promotion
For the conversion function that returns an object of the type int
there is used a conversion that has a less rank than the floating-point promotion.
That is a conversion function with the promotion rank is more viable than a function that has the conversion rank.
In these declarations
long double b = Name();
bool c = Name();
there are used conversions from the type int and float correspondingly to the type long double and bool. So neither conversion is better. The both functions have the conversion rank.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | |
Solution 2 |