0

I successfully built an overloaded operator+(Global left, int right) for a template class in global scope named Global.

template <typename T>
class Global {
public:
    Global operator+(const int& right) const
    {
        cout << "Using Global overloaded operator+" << endl;

        return *this;
    }
};

Since addition is commutative, I also created the other overloaded operator+(int left, Global right) to allow the commutable operation.

template <typename T>
Global<T> operator +(int left, Global<T> right)
{
    return right + left;
}

Here is my attempt to do the same thing for a Nested Class.

template <typename T>
class Container {
public:
    class Nested {
    public:
        Nested operator+(const int& right) const
        {
            cout << "Using Nested overloaded operator+" << endl;

            return *this;
        }
    };
};

template <typename T> // The following line is critical
typename Container<T>::Nested operator+(int left, typename Container<T>::Nested right)
{// Both 'typename' are necessary to avoid extra compilation errors
    return right + left;
}

Now when I try to execute the following code to test the operator overloads, I get some compilation errors when trying to use the commutable operator+ from the Nested class, mainly "Error C2783 - 'Container::Nested operator +(int,Container::Nested)': could not deduce template argument for 'T'", but also "Error E0349 - no operator "+" matches these operands".

int main(void)
{
    Global<int> global;

    global + 2; // Works perfectly
    2 + global; // Works perfectly

    Container<int>::Nested nested;

    nested + 2; // Works perfectly
    2 + nested; // Compilation Error C2783 and E0349

    system("pause"); // Everything works fine without the line above

    return 0;
}

I am using Visual Studio 15.5.2 with /std:c++latest enabled. If possible, I would like the operator+ to be defined inside the Nested class definition.

Nighteen
  • 731
  • 1
  • 7
  • 16
  • `Global operator +(int left, typename Global right)` should be `Global operator +(int left, Global right)`. There is no need for `typename` there – Fureeish Jan 12 '18 at 02:01
  • The Global operator+ is completely fine. If you meant the Nested operator+, I tried removing the typenames to be "Container::Nested operator+(int count, Container::Nested iterator)". The compiler throws a lot of extra errors that have nothing to do with the operator+ such as **Error C2065 'global': undeclared identifier**. The same happens if I remove only one of the 'typename'. – Nighteen Jan 12 '18 at 02:04
  • with the `typename` in `Global operator +` my compiler gives an error for unnecessary `typename`... – Fureeish Jan 12 '18 at 02:07
  • If I understood correctly, I tried to switch this line `typename Container::Nested operator+(int left, typename Container::Nested right)` into this `Container::Nested operator+(int left, typename Container::Nested right)` – Nighteen Jan 12 '18 at 02:10
  • You misunderstood then. I copy-pasted the **exact** code you posted. I meant to delete the `typename` in your function provided in the **second** block of code, which is: `Global operator +(int left, typename Global right)`. The `typename` **is wrong here**. – Fureeish Jan 12 '18 at 02:11
  • But the second block of code is already working perfectly, the problem happens when I try to use the Nested operator. Tried to change the second block of code as suggested but as expected nothing changes regarding the errors in the third/fourth block of code, even though the second block of code still works without the 'typename', let me remove it from the question to avoid extra confusions. – Nighteen Jan 12 '18 at 02:14
  • I'd recommend making both operator overloads non-members: `operator+(Global, int)` and `operator+(int, Global)`. Not only does it make the code look more symmetric, it can make a difference in behavior. If an implicit conversion from the type of `x` to `Global` exists, in the version with a member operator, `2+x` will work but `x+2` will not. – aschepler Jan 12 '18 at 12:18

1 Answers1

2

As seen in this answer, the template deduction is far more complicated in this case than one might think. To fix this you can declare the function as friend inside your Nested class, like so:

template <typename T>
class Container {
public:
    class Nested {
    public:
        Nested operator+(const int& right) const
        {
            std::cout << "Using Nested overloaded operator+" << std::endl;

            return *this;
        }
        // moved here and declared as friend, instead of declaring it somewhere else
        friend Nested operator+(int left, Nested right)
        {
            return right + left;
        }
    };
};

By doing this, you also avoid using double typename and Container<T>:: (thanks @Jarod42) in the signatue.

Fureeish
  • 12,533
  • 4
  • 32
  • 62
  • I understood that the extra `typename` in the Global class was unnecessary, let's remove it from the question since it has nothing to do with it. Thanks for your quick, well-formatted and correct answer. – Nighteen Jan 12 '18 at 02:21
  • @user2565020 agreed, I deleted the parts regarding it. Always happy to help – Fureeish Jan 12 '18 at 02:23