类模板上的运算符重载

26
我在为模板类定义一些运算符重载遇到了一些问题。让我们以这个假设的类为例。
template <class T>
class MyClass {
  // ...
};

operator+=

// In MyClass.h
MyClass<T>& operator+=(const MyClass<T>& classObj);

// In MyClass.cpp
template <class T>
MyClass<T>& MyClass<T>::operator+=(const MyClass<T>& classObj) {
    // ...
    return *this;
}

在这个编译器错误中出现了以下结果:
no match for 'operator+=' in 'classObj2 += classObj1'

operator<<

// In MyClass.h
friend std::ostream& operator<<(std::ostream& out, const MyClass<T>& classObj);

// In MyClass.cpp
template <class T>
std::ostream& operator<<(std::ostream& out, const MyClass<T>& classObj) {
    // ...
    return out;
}

在这个编译器警告中显示的结果:
friend declaration 'std::ostream& operator<<(std::ostream&, const MyClass<T>&)' declares a non-template function

我在这里做错了什么?

你能发一些无法编译的真实代码吗? - Naveen
@Naveen:你可以在http://www.box.net/shared/v23rj2f8e7获取一个压缩版本。 - Pieter
5个回答

25

由于您建立了整个 模板,而不仅仅是它的特殊化,因此您需要这样说(在这种情况下,您只需要在operator<<之后添加<>):

template<typename T>
friend std::ostream& operator<<(std::ostream& out, const MyClass<T>& classObj);

实际上,除非它访问私有或受保护的成员,否则没有必要将其声明为友元。由于您只收到一个警告,因此您的友元声明似乎不是一个好主意。如果您只想声明它的一个特定专业领域作为友元,可以像下面所示那样进行操作,在类之前对模板进行前向声明,以便operator<<被识别为模板。

// before class definition ...
template <class T>
class MyClass;

// note that this "T" is unrelated to the T of MyClass !
template<typename T>
std::ostream& operator<<(std::ostream& out, const MyClass<T>& classObj);

// in class definition ...
friend std::ostream& operator<< <>(std::ostream& out, const MyClass<T>& classObj);

上述两种方式都将特化声明为友元,但第一种方式将所有特化声明为友元,而第二种方式仅将operator<<的特化声明为友元,并且该特化的T与授予友情的类的T相等。

在另一种情况下,您的声明看起来没问题,但请注意,当声明中的TU是不同类型时,您不能将MyClass<T>MyClass<U>进行+=运算(除非这些类型之间存在隐式转换)。您可以将+=定义为成员模板。

// In MyClass.h
template<typename U>
MyClass<T>& operator+=(const MyClass<U>& classObj);


// In MyClass.cpp
template <class T> template<typename U>
MyClass<T>& MyClass<T>::operator+=(const MyClass<U>& classObj) {
  // ...
  return *this;
}

18
// In MyClass.h
MyClass<T>& operator+=(const MyClass<T>& classObj);


// In MyClass.cpp
template <class T>
MyClass<T>& MyClass<T>::operator+=(const MyClass<T>& classObj) {
  // ...
  return *this;
}

这对于模板来说是无效的。操作符的完整源代码必须在使用它的所有翻译单元中都存在。通常这意味着代码在头文件中是内联的。
编辑:根据标准,理论上可以导出模板,但很少有编译器支持。此外,如果模板在MyClass.cpp中明确实例化了所有类型为T-,则也可以执行上述操作,但实际上,这通常违背了模板的初衷。
更多编辑:我看了你的代码,需要一些修改,例如重载operator[]。此外,通常我会将维度作为模板参数的一部分,允许在编译时捕获+或+=的失败,并允许类型有意义地堆栈分配。您的异常类还需要从std :: exception派生。但是,这些都不涉及编译时错误,它们只是不太好的代码。

10

这篇文章帮助了我解决了同样的问题。

解决方法:

  1. 在类的定义之前先进行friend函数的前向声明。例如:

  2.    template<typename T> class MyClass;  // pre-declare the template class itself
       template<typename T> std::ostream& operator<< (std::ostream& o, const MyClass <T>& x);
    
  3. 在类中声明友元函数时,在函数名后添加"<>"。

  4.    friend std::ostream& operator<< <> (std::ostream& o, const Foo<T>& x);
    

0

你必须指定这个朋友是一个模板函数:

MyClass<T>& operator+=<>(const MyClass<T>& classObj);

请参考this的C++ FAQ Lite答案了解详情。


-3
这种方式可行:
class A
{
    struct Wrap
    {
        A& a;
        Wrap(A& aa) aa(a) {}
        operator int() { return a.value; }
        operator std::string() { stringstream ss; ss << a.value; return ss.str(); } 
    }
    Wrap operator*() { return Wrap(*this); }
};

这里的模板在哪里? - Patrizio Bertoni

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接