【问题标题】:Operator overloading on class templates类模板上的运算符重载
【发布时间】:2011-04-30 04:21:47
【问题描述】:

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

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'
    
  • 运营商

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


【解决方案1】:

您需要说以下内容(因为您与整个 模板 成为朋友,而不仅仅是一个专门化的模板,在这种情况下,您只需在 operator&lt;&lt; 之后添加一个 &lt;&gt;) :

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

实际上,除非它访问私有或受保护成员,否则无需将其声明为朋友。由于您刚刚收到警告,看来您的友谊声明不是一个好主意。如果您只想将它​​的单个特化声明为朋友,您可以如下所示进行,在您的类之前使用模板的前向声明,以便 operator&lt;&lt; 被识别为模板。

// 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&lt;&lt;的特化声明为T的朋友等于授予友谊的班级的T

在另一种情况下,您的声明看起来不错,但请注意,当 TU 与该声明的类型不同时,您不能将 +=MyClass&lt;T&gt; 转换为 MyClass&lt;U&gt;(除非您有这些类型之间的隐式转换)。您可以将您的+= 设为会员模板

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

【讨论】:

    【解决方案2】:
    // 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 类型显式实例化,您也可以执行上述操作,但实际上,这通常违背模板的意义。

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

    【讨论】:

      【解决方案3】:

      This helped me 有完全相同的问题。

      解决方案:

      1. class 本身的定义之前转发声明 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. 在你的类中声明你的朋友函数,并在函数名称后附加“”。

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

      【讨论】:

        【解决方案4】:

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

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

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

        【讨论】:

          【解决方案5】:

          这种方式有效:

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

          【讨论】:

          • 模板在哪里?
          猜你喜欢
          • 1970-01-01
          • 2012-02-07
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2010-11-01
          • 2013-02-05
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多