运算符重载类模板

时间:2010-10-25 11:59:31

标签: c++ templates operator-overloading

我在为模板类定义一些运算符重载时遇到了一些问题。让我们以这个假设的课程为例。

template <class T>
class MyClass {
  // ...
};
  • 运算符+ =

    // 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'
    
  • 运营商LT;&LT;

    // 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
    

我在这里做错了什么?

5 个答案:

答案 0 :(得分:13)

您需要说明以下内容(因为您与整个模板建立了联系,而不仅仅是它的特化),在这种情况下,您只需要在{{{{}}之后添加<> 1}}):

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); 的专业化为朋友,{ {1}}等于授予友谊的类的operator<<

在另一种情况下,您的声明看起来不错,但请注意,TT时,您+= MyClass<T> MyClass<U> T具有该声明的不同类型(除非您在这些类型之间进行隐式转换)。您可以将U设为会员模板

+=

答案 1 :(得分:10)

// 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派生。但是,这些都不涉及编译时错误,它们只是不是很好的代码。

答案 2 :(得分:4)

http://www.parashift.com/c++-faq-lite/template-friends.html

这帮助了我完全相同的问题。

Soln:

  1. 在类本身的定义之前转发声明friend函数。例如:

       template<typename T> class MyClass;  // pre-declare the template class itself
       template<typename T> std::ostream& operator<< (std::ostream& o, const MyClass <T>& x);
    
  2. 使用“&lt;&gt;”在您的班级中声明您的朋友功能附加到函数名称。

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

答案 3 :(得分:0)

您必须指定朋友是模板功能:

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

有关详细信息,请参阅this C ++ FAQ Lite答案。

答案 4 :(得分:-1)

这种方式有效:

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