Why conversion function is not used for an object when it is assigned to?
Asked Answered
E

2

13

I learned that we could provide conversion operators for our classes in C++. So I expected that for the following program, c=1; would've used the conversion operator int(). But to my surprise; that doesn't happen and we get a compiler error saying that

error: no match for 'operator=' (operand types are 'C' and 'int').

So I want to know why isn't the conversion operator used here.

struct C {
    explicit C(int);
    operator int&(); 
};

int main() {
    C c({});
    c = 1;   //this gives error. Why the conversion operator int&() is not used here?
}

Note that I know that I can solve the error if I just remove the explicit keyword from the constructor. But my question is about why the conversion operator is not used.

I thought that since we have a conversion operator for our class, the class object can be converted to an int so that it can be assigned to.

Erotic answered 24/4, 2023 at 13:35 Comment(10)
The conversion operator goes the other way: int i = c;.Pontone
@PeteBecker I want to know why it doesn't go other way here. I mean c can be converted to an int here.Erotic
Because C++ doesn't work this way. c = 1 does not "convert to an int". After all is said and done, you still have a C remaining, and not an int. C++ has rules for everything. If you want it to work this way, that's what operator= is for. operator= is for assigning to an instance of a class. A conversion operator is for assigning from an instance of a class.Haines
@SamVarshavchik I want to know that since we have a conversion operator for our class so our class object can be converted to an int so that it can be assigned to.Erotic
If you want to convert an instance of the class to an int, then define operator int(), and then int d=c will work. Those are your options. That's the only way that C++ works.Haines
@Erotic I learnt that we can provide conversion operators for our classes in C++ -- This is an opinion-based comment, but you learned one of the most bug-prone aspects of C++. For a non-trivial program, can you tell when or where the conversion operator will be used? I bet not -- code that you didn't expect being invoked all of a sudden is invoked. That's why the standard library hardly uses this. For examplec_str() and not overloading const char * is done for std::string.Laporte
@Laporte Sorry I recently started learning C++ and read about conversion to bool that some classes provide in standard library. So I tried writing my own program to learn more about it after reading about it in C++ Primer. I didn't see anything opinion based in that comment of mine.Erotic
@Erotic -- I suggest to use conversion operators sparingly. Don't have your entire codebase rely on these silent conversions -- take it from me, it can lead to very hard-to-find bugs.Laporte
@Sam: "I didn't see anything opinion based in that comment of mine." He's saying that his own comment is opinion based.Rouge
There is an 'ingoing' and 'outgoing' conversion. Ingoing is implemented by the non-explicit constructor with exactly one argument, outgoing is implemented with an operator Type() member function. If you convert from your class A to your class B you can use either of those conversion function mechanisms (put into the respective correct class of those two). As in the example you want to convert from the built-in int only the constructor solution works.Grip
M
14

I thought that since we have a conversion operator for our class, the class object can be converted to an int so that it can be assigned to.

Because the user-defined conversions are not considered for the left hand operand of built-in assignment operator. This can be seen from Operators in expression's documentation:

For the built-in assignment operators, conversions of the left operand are restricted as follows:

  • no temporaries are introduced to hold the left operand, and
  • no user-defined conversions are applied to the left operand to achieve a type match with the left-most parameter of a built-in candidate.

(emphasis mine)

This means that the program is ill-formed.

Manteau answered 24/4, 2023 at 13:51 Comment(2)
"x = y always means x.operator=(y) if x is has a class type" is the clearest way I've seen this saidAerostat
@Aerostat Yup for a layman that should be good enough. Only if C++ was that simple(or had that simple wording).Manteau
M
4

For the formal explanation refer to this answer. I'll try to provide an intuition for why this does not work the way you expected. In your question, you try to work out the following expression

c = 1;

where c is an instance of class C. We can make two ways of working this out.

  • Making an assignment operator accepting argument of type int
  • Making an implicit constructor accepting int.

So if we work with the expression mentioned, above should be sufficient.

However, one might want to write something like this.

int i = c; // again, c is instance of C

We also (if we try to think how a language designer might have thought) need to work this out. So the designers for this purpose decided to make a conversion operator which is especially for cases like this.

In summary

  • If we want to make A from B, we define a constructor of A which accepts B
  • If we also want to get B from A(and we can't or don't want to define a constructor of B which accepts A), we make a conversion operator which converts A to B as we wish.
Miche answered 24/4, 2023 at 19:46 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.