2
#include <iostream>
using namespace std;

class StringNum {
public:
    string s;
    StringNum() {s = "";}
public:
    StringNum(int n) {
        s = "";
        for (int i=1; i<=n; i++) s += "x";
    }

    operator int () {
        return s.length();
    }

    StringNum operator + (StringNum v) {
        cout << "operator + is called\n";
        int len = s.length() + v.s.length();
        StringNum res;
        for (int i=1;i<=len;i++) res.s += "x";
        return res;
    }

    template <class T>
    StringNum operator + (T value) {
        return (*this) + StringNum(value);
    }
};

template<class T>
StringNum operator + (T value, const StringNum& num) {
    cout << "operator + opposite is called\n";
    //return value + num; // infinite recursion, of course
    // return num + value;  // infinite recursion, despite StringNum + <class T> is defined
    return num + StringNum(value); // STILL infinite recursion
    //return StringNum(num) + value; // correct, output 6
}

int main()
{
    StringNum x(4);
    cout << (x + 2.5) << "\n"; // StringNum + <class T>, output 6
    int res = (2 + x);
    cout << res;
    return 0;
}

Class StringNum represents an integer number > 0, where length of the string is the number.

StringNum + StringNum are member functions and work correctly.

StringNum + <class T> is also a member function and works correctly.

However, for <class T> + StringNum, it requires a external function. However, the behavior of operator + is confusing and doesn't make any sense:

template<class T>
StringNum operator + (T value, const StringNum& num) {
    cout << "operator + opposite is called\n";
    //return value + num; // infinite recursion, of course
    // return num + value;  // StringNum + <class T>, infinite recursion. Why??
    return num + StringNum(value); // STILL infinite recursion
    //return StringNum(num) + value; // StringNum + <class T> -> this time it's correct, output 6
}

How is it that num + StringNum(value) causes infinite recursion, while it should call StringNum + StringNum ? Also, why does num + value cause infinite recursion, while it should call StringNum + <class T> ? Finally, how does StringNum(num) + value solve the problem when num is a StringNum in the first place?

How can I correctly implement commutative operator + in this case ? Thank you.

Huy Le
  • 1,439
  • 4
  • 19
  • Try `StringNum operator+(const StringNum& op1, const StringNum& op2)` as a non member function. See https://stackoverflow.com/q/4622330/10077 – Fred Larson Feb 14 '20 at 14:04
  • `s = ""; for (int i=1; i<=n; i++) s += "x";` Can be replaced by `s = std::string(n, 'x');`. – Jarod42 Feb 14 '20 at 14:42

1 Answers1

3

Use correct constness:

StringNum operator + (const StringNum& v) const {
    cout << "operator + is called\n";
    int len = s.length() + v.s.length();
    StringNum res;
    for (int i=1;i<=len;i++) res.s += "x";
    return res;
}

template <class T>
StringNum operator + (T value) const {
    return (*this) + StringNum(value);
}

Demo

As In your template,

You call operator+ with const StringNum& and StringNum

And candidates are:

  • StringNum StringNum::operator + (StringNum v) Doesn't match, apply only to non const lhs
  • template <class T> StringNum StringNum::operator + (T value) Doesn't match, same reason as above
  • template<class T> StringNum operator + (T value, const StringNum& num) Matches, so leading to infinite recursion.
Jarod42
  • 203,559
  • 14
  • 181
  • 302
  • Do you mean the result of operator should ALWAYS be const ? Edit: my mean the final const keyword. – Huy Le Feb 14 '20 at 14:09
  • @HuyĐứcLê *Do you mean the result of operator should ALWAYS be const ?* -- Which `const` are you referring to? The argument should have been passed as `const` reference, and since the `+` function doesn't mutate any members of `StringNum`, should be marked as a `const` function. – PaulMcKenzie Feb 14 '20 at 14:11
  • I mean the "doesn't mutate any members" const. But could you explain how does that solve the infinite recursion (calling the wrong operator) problem ? – Huy Le Feb 14 '20 at 14:12
  • 1
    @HuyĐứcLê your global operator+ function take const StringNum parameter. You can not call non-const member function with const class variable. So member operator+ function was not eligable – idris Feb 14 '20 at 14:19
  • Ohhh. I remember that now. Thank you. – Huy Le Feb 14 '20 at 14:23