Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

casting operator() - cast to reference and cast to value

My Concern is touching the subject given in the title.

Suppose we have got some very simple class

class Integer{
public:
    Integer(int number) : m_value(number) {}
    int value(){return m_value;}
private:
    int m_value;
};

Now we can use this class, that represents int, of course there is no bigger sense in using this class, but it's just an example. If want this class to behave more like a real integer, then we should provide casting operators (not mentioning operator ==, >, < etc.) and here is my concern, because I can define two operators:

operator T() {return m_value;}
operator T&() {return m_value;}

some easiest examples compiles and works as such with both of them (first or second), so our class can be as follows:

class Integer{
public:
    Integer(int number) : m_value(number) {}
    int value(){return m_value;}
    operator T(){return m_value;} // casting operator
private:
    int m_value;
};

But it can be:

class Integer{
public:
    Integer(int number) : m_value(number) {}
    int value(){return m_value;}
    operator T&(){return m_value;} // casting operator
private:
    int m_value;
};

As well, so my question is which of those two are appropriate? Of course I cannot have both of them, because compiler would not be able to recongnize which one to use.

Naturally reference casting seems to be more effective, but I am not sure if it would work always the way it should work. Could please advice me somehow and say, why one operator is better than another?

like image 221
DawidPi Avatar asked Feb 09 '23 12:02

DawidPi


1 Answers

As a matter of fact, you need both and with a bit of tweaking, the compiler will know which to choose. All the magic is in the fact that you can (and should, when it makes sense) define a member function to be const, id est being callable from a constant object.

Hence, your Integer class should look like

class Integer
{
public:
    Integer() : Integer(0) {}
    Integer(int number) : m_value(number) {}
    Integer(const Integer& other) : m_value(other.value()) {}
    int value() const { return m_value; }

    operator int() const { return m_value; }
    operator int&() { return m_value; }
    const Integer& operator=(const Integer& other) { m_value = other; return *this; }
private:
    int m_value;
};

This definition would allow the Integer class to be usable in those following cases:

#include <iostream>
int main()
{
    const Integer zero;
    const Integer one(1);
    Integer counter;

    counter = zero + one;
    std::cout << "counter: " << counter << std::endl;

    counter++;
    std::cout << "counter: " << counter << std::endl;

    for (Integer i=0 ; i < counter ; ++i)
    {
        std::cout << "i: " << i << std::endl;
    }

    return zero;
}

Compile & run: g++ -std=c++14 -O2 -Wall -pedantic -pthread main.cpp && ./a.out

Output:

counter: 1
counter: 2
i: 0
i: 1

Live example: http://coliru.stacked-crooked.com/a/641fe02e70c02920

like image 184
YSC Avatar answered Feb 11 '23 01:02

YSC