运算符重载类模板

Pie*_*ter 14 c++ templates operator-overloading

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

template <class T>
class MyClass {
  // ...
};
Run Code Online (Sandbox Code Playgroud)
  • 操作者+ =

    // 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;
    }
    
    Run Code Online (Sandbox Code Playgroud)

    导致此编译器错误:

    no match for 'operator+=' in 'classObj2 += classObj1'
    
    Run Code Online (Sandbox Code Playgroud)
  • 运营商<<

    // 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;
    }
    
    Run Code Online (Sandbox Code Playgroud)

    结果在此编译器警告:

    friend declaration 'std::ostream& operator<<(std::ostream&, const MyClass<T>&)' declares a non-template function
    
    Run Code Online (Sandbox Code Playgroud)

我在这做错了什么?

Joh*_*itb 13

你需要下面要说的(因为你善待整个模板,而不是只是它的专业化,在这种情况下,你只需要添加一个<>operator<<):

template<typename T>
friend std::ostream& operator<<(std::ostream& out, const MyClass<T>& classObj);
Run Code Online (Sandbox Code Playgroud)

实际上,除非访问私人或受保护的成员,否则无需将其声明为朋友.既然你刚收到警告,那么你的友情宣言似乎不是一个好主意.如果你只是想将它作为朋友声明一个特殊化,你可以像下面所示那样做,在你的类之前使用模板的前向声明,这样就可以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);
Run Code Online (Sandbox Code Playgroud)

以上和这种方式都将它的特化声明为朋友,但第一个声明所有特化作为朋友,而第二个仅宣称operator<<作为朋友的专业化,其T等于T授予友谊的类的专业.

而在另一种情况下,你的声明看起来不错,但要注意,你不能+=一个MyClass<T>一个MyClass<U>的时候TU不同的类型与声明(除非你有这些类型之间的隐式转换).您可以成为+=会员模板

// 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;
}
Run Code Online (Sandbox Code Playgroud)


Pup*_*ppy 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;
}
Run Code Online (Sandbox Code Playgroud)

这对模板无效.运算符的完整源代码必须位于其使用的所有转换单元中.这通常意味着代码在标题中内联.

编辑:从技术上讲,根据标准,可以导出模板,但很少有编译器支持它.此外,如果模板在MyClass.cpp中为所有类型的T-显式实例化,您也可以执行上述操作,但实际上,这通常会违反模板的要点.

更多编辑:我读了你的代码,它需要一些工作,例如重载operator [].另外,通常,我会将维度作为模板参数的一部分,允许在编译时捕获+或+ =的失败,并允许类型有意义地堆栈分配.您的异常类还需要从std :: exception派生.但是,这些都不涉及编译时错误,它们只是不是很好的代码.


use*_*478 5

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

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

索恩:

  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);
    
    Run Code Online (Sandbox Code Playgroud)
  2. 在类中声明您的朋友函数,并在函数名称后附加“ <>”。

       friend std::ostream& operator<< <> (std::ostream& o, const Foo<T>& x);
    
    Run Code Online (Sandbox Code Playgroud)