Коммутативный оператор + перегрузка вызывает бесконечную рекурсию - PullRequest
2 голосов
/ 14 февраля 2020
#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;
}

Класс StringNum представляет целое число> 0, где длина строки - это число.

StringNum + StringNum - функции-члены и работают правильно.

StringNum + <class T> - также является функцией-членом и работает правильно.

Однако для <class T> + StringNum требуется внешняя функция. Однако поведение operator + сбивает с толку и не имеет никакого смысла:

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
}

Как получается, что num + StringNum(value) вызывает бесконечную рекурсию, тогда как она должна вызывать StringNum + StringNum? Кроме того, почему num + value вызывает бесконечную рекурсию, тогда как она должна вызывать StringNum + <class T>? Наконец, как StringNum(num) + value решает проблему, когда num является StringNum на первом месте?

Как правильно реализовать commutative operator + в этом случае? Спасибо.

1 Ответ

3 голосов
/ 14 февраля 2020

Используйте правильное постоянство:

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);
}

Демо

Как и в вашем шаблоне,

Вы звоните operator+ с const StringNum& и StringNum

И кандидаты:

  • StringNum StringNum::operator + (StringNum v) Не совпадает, применяется только к неконстантным lhs
  • template <class T> StringNum StringNum::operator + (T value) Не совпадает, та же причина, что и выше
  • template<class T> StringNum operator + (T value, const StringNum& num) Соответствует, что приводит к бесконечной рекурсии.
...