Why objects of class A are converted to bool (or to int) in the following code:
class A
{
public:
operator bool() const { return true; }
operator int() const { return 1; }
};
int main()
{
return A() == A();
}
and it is not clear what are they converted to? to bool or to int?
Class conversion can be done with the help of operator overloading. This allows data of one class type to be assigned to the object of another class type.
There are two types of user-defined conversions: Conversion constructors and conversion functions. The compiler can use only one user-defined conversion (either a conversion constructor or a conversion function) when implicitly converting a single value.
We need to find what to do with ==
. That's going to involve looking for member, non-member, and built-in candidates for ==
. In this case, we don't have any member/non-member candidates, so that part is easy.
The built-in candidates are, from [over.built]/13 (emphasis mine, and abridged):
For every pair of promoted arithmetic types L and R, there exist candidate operator functions of the form
bool operator==(L, R);
The promoted arithmetic types are the integral types after promotion and the floating point types. Any integral type smaller than int
(including bool
) promotes to int
. (float
promotes to double
, but float
is still a "promoted arithmetic type"). The important part of this for us really is that the "promoted arithmetic types" include int
, but not bool
. So effectively, we have built-in candidates like:
bool operator==(int, int);
bool operator==(int, long);
bool operator==(long, int);
bool operator==(long, long);
bool operator==(int, float);
// etc.
There are a lot of candidates in this set. But we can basically divide them into two groups.
The first group consists entirely of:
bool operator==(int, int);
This candidate is viable, we have a clear best conversion sequence since going through operator int() const
is better than going through operator bool() const
and then promoting.
The second group consists of every other candidate. For every promoted arithmetic type that is not int
, we have two equivalent conversion sequences: one through the bool
conversion and one through the int
conversion. Neither is better than the other. When I first wrote this answer, I thought that this meant these candidates would be rejected - but that is surprisingly not the case, as T.C. points out: an ambiguous conversion sequence is treated equivalently to any other user-defined conversion sequence.
So from the first group, we have one viable candidate which involves a user-defined conversion sequence. And from the second group, we have a lot of candidates with ambiguous conversion sequences - which importantly are considered equivalently good to the operator==(int, int)
candidate from the first group.
As a result, A() == A()
is ill-formed. There is no best viable candidate. gcc is wrong to accept this.
Note that gcc does reject very similar other presentations of this same idea:
void check(int, int);
void check(float, float);
check(A(), A()); // gcc and clang reject, msvc accepts
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With