Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Objects of a class that does not have operator ==() are converted to another type

Tags:

c++

c++17

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?

like image 239
Alexey Starinsky Avatar asked Feb 08 '19 20:02

Alexey Starinsky


People also ask

How to convert one class type to another class type?

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.

How many types are there in user defined conversion?

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.


1 Answers

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
like image 115
Barry Avatar answered Oct 17 '22 23:10

Barry