如何为模板嵌套类编写可通过重载的算术运算符?

时间:2018-01-12 01:40:07

标签: c++ templates nested operator-overloading

我成功为名为全局的全局范围内的模板类构建了一个重载运算符+(全局左, int 右)。

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

        return *this;
    }
};

由于加法是可交换的,我还创建了另一个重载运算符+( int 左,全局右)以允许可换行操作。

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

这是我尝试为嵌套类做同样的事情。

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

现在,当我尝试执行以下代码来测试运算符重载时,在尝试使用嵌套类中的commutable operator +时出现了一些编译错误,主要是“错误C2783 - 'Container :: Nested operator + (int,Container :: Nested)':无法推断'T'的模板参数“,但”错误E0349 - 没有运算符“+”匹配这些操作数“

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

我在启用 / std:c ++最新的情况下使用Visual Studio 15.5.2。如果可能的话,我希望在嵌套类定义中定义operator +。

1 个答案:

答案 0 :(得分:2)

this answer所示,在这种情况下,模板推导要比人们想象的要复杂得多。要解决此问题,您可以在friend类中将该函数声明为Nested,如下所示:

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

通过这样做,您还可以避免在签名中使用双typenameContainer<T>::感谢@ Jarod42 )。