Search code examples
c++operator-overloadingtypecast-operator

Overloading operators for class with cast operator and single-argument constructor


I have such code

class Number
{
    int m_value;

public :
    Number(const int value) : 
        m_value(value)
    {
    }

    operator const int() const
    {
        return m_value;
    }

    int GetValue() const
    {
        return m_value;
    }
};

bool operator==(const Number& left, const Number& right)
{
    return left.GetValue() == right.GetValue();
}

class Integer
{
    int m_value;

public :
    Integer(const int value) : 
        m_value(value)
    {
    }

    operator const int() const
    {
        return m_value;
    }

    bool operator==(const Integer& right) const
    {
        return m_value == right.m_value;
    }

    bool operator==(const int right) const
    {
        return m_value == right;
    }

    int GetValue() const
    {
        return m_value;
    }
};

bool operator==(const int left, const Integer& right)
{
    return left == right.GetValue();
}

int main()
{
    Number n1 = 1;
    Number n2 = 1;
    int x3 = 1;

    n1 == n2;
    n1 == x3; // error C2666: 'operator ==' : 3 overloads have similar conversions
    x3 == n1; // error C2666: 'operator ==' : 2 overloads have similar conversions

    Integer i4 = 1;
    Integer i5 = 1;

    i4 == i5;
    i4 == x3;
    x3 == i4;

    return 0;
}

For class Number I have two errors as shown in the code above. For class Integer everything is OK. The problem is, I want to keep in resulting class single-parameter constructor, cast operator and equality operations (MyClass == int, int == MyClass, MyClass == MyClass), but I want to implement only one version of operator== as in class Number. I don't see any way to do this. Is that even possible or I must have all three implementations as in class Integer? I know why I get these errors I just don't like the solution I have.


Solution

  • In class Number you define a conversion operator to int and your constructor allows converting an int to a Number. Therefore, when comparing a Number n and an int x for equality, ambiguity arises: should the compiler invoke the built-in operator == for ints and convert n to an int, or should it rather pick your operator and convert x to a Number? Both conversions are equally good, and it can't choose one.

    So yes you have to define three versions, or add a template operator which can perfectly match the type of all arguments and forward to your operator explicitly, like this one (but you most likely want to guard it with some enable_if to limit its applicability only to the appropriate T and U):

    template<typename T, typename U> // beware: this will match anything. to be constrained
    bool operator == (T n, U const& u)
    {
        return (Number(n) == Number(u));
    }