在类模板上的操作者重载

问题描述 投票:17回答:5

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

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
    

我在这里做错了什么?

c++ templates operator-overloading
5个回答
12
投票
// 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。然而,这些都不涉及编译时的错误,只是代码不怎么样。


15
投票

你需要说下面的话(因为你结交了一个完整的 模板 而不是仅仅是它的一个特殊化,在这种情况下,您只需要添加一个 <> 之后 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 的类授予友谊。

而在另一种情况下,你的声明看起来是可以的,但请注意,你不能 += a 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;
}

5
投票

这对我有帮助 有着完全相同的问题。

解决办法。

  1. 向前声明 friend 函数的定义之前的 class 本身。例如:在你的类中声明你的友情函数。

       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. 在你的类中声明你的朋友函数,并在函数名后面加上"<>"。

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

0
投票

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

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

参见 这个 C++常见问题精简版答案详解。


-2
投票

这种方式可行。

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); }
};
© www.soinside.com 2019 - 2024. All rights reserved.