2

I'm currently learning how implicitly defined conversion operators (also known as user-defined conversions) work for a given class. In my particular case, I wanted to test out my class to be implicitly converted to the default integer type. Found below is my code snippet.

#include <iostream>

using std::cout;
using std::cin;
using std::endl;

class A {
    public:
        A(int);
        operator int() const;
    protected:
        int value;
};

A::A(int input) : value(input) {
}

A::operator int() const {
    return this->value;
}

int main() {
    A foo = 1; 
    foo = foo + 1;          // no error
    foo = foo * 1;          // no error
    foo = foo / 1;          // no error
    cout << foo << endl;    // no error
    !foo;                   // no error
    &foo;                   // no error
    foo%1;                  // no error
    foo != 1;               // no error
    foo == 1;               // no error
    foo >= 1;               // no error
    foo <= 1;               // no error
    foo < 1;                // no error
    foo > 1;                // no error
    foo && 1;               // no error
    foo || 1;               // no error
    A *boo = &foo;          // no error
    *boo = 5;               // no error
    cin >> foo;             // error
    foo *= 2;               // error
    foo++;                  // error
    return 0;
}

As you can see, these operators provide no errors, but the >>, *=, and ++ yield errors; i.e. the object of class A is not implicitly converted for these operators. I noticed that it isn't converted for similar assignment operators. Can someone explain why this is the case, and what the supported operators are for implicit user conversions?

Chronollo
  • 322
  • 1
  • 9
  • Essential read 1st: [What are the basic rules and idioms for operator overloading?](https://stackoverflow.com/questions/4421706/what-are-the-basic-rules-and-idioms-for-operator-overloading) – πάντα ῥεῖ Sep 13 '20 at 19:14
  • You can only use operators which require a const value with your overload. Operators which change the left hand site operand cannot be used with the converison operator. – πάντα ῥεῖ Sep 13 '20 at 19:17
  • @πάνταῥεῖ Thank you for the prompt response. I already read the implicit conversion operator section for that document, and it doesn't specify the supported operations for implicit user conversions. It only mentions the use of them, and how they can be misused. – Chronollo Sep 13 '20 at 19:18
  • @πάνταῥεῖ I see. Just to clarify, operators that change the left hand side operand cannot be used with the conversion operator _generally_ or because I've specified the const in the operator overload? – Chronollo Sep 13 '20 at 19:21
  • @πάνταῥεῖ So the only way for my class A to completely behave like an integer is to manually overload the `++`, `*=`, etc operators? Since those are supported with the primitive/default integer type. – Chronollo Sep 13 '20 at 19:23
  • 2
    No, see the answer. You just need a conversion to `int&`. – cigien Sep 13 '20 at 19:24
  • Great pair of Q&A. Really rare these days at SO's [tag:c++] section. A pearl in the sand. – πάντα ῥεῖ Sep 13 '20 at 19:27
  • @cigien Thank you!! I tried that and it worked. – Chronollo Sep 13 '20 at 19:31
  • Please read my answer, and if you have any questions about the specific answer, ask them there. – cigien Sep 13 '20 at 19:32

1 Answers1

4

These operators:

cin >> foo;  // >> endl is a bug     
foo *= 2;               
foo++;  

can only be called on an l-value. Your conversion operator returns a temporary int, which is not an l-value. Also, your operator is const qualified, which means it can only be called on const A instances.

You need to provide a conversion operator that returns an l-value like this:

class A {
    public:
        operator int&();
    // ...
};

A::operator int&() {
    return this->value;
}

Note that this operator can't be const if you want it to return a modifiable l-value.

Here's a demo.

cigien
  • 57,834
  • 11
  • 73
  • 112