2010-10-25 89 views
11

我有一些问题,为模板类定义一些运算符重载。举个例子,我们假设这个假设的类。运营商在类模板上重载

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 
    

我在做什么错在这里?

+0

你可以发布它无法编译一些实际的代码? – Naveen 2010-10-25 12:08:33

+0

@Naveen:您可以在http://www.box.net/shared/v23rj2f8e7获得压缩版本 – Pieter 2010-10-25 12:12:11

回答

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

0

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

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

this C++ FAQ精简版答案的详细信息。

12

你需要下面要说的(因为你善待整个模板而不只是它的专业化,在这种情况下,你只需要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授予友谊的班级。

而在另一种情况下,你的声明看起来不错,但要注意,你不能+=一个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; 
} 
2

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

帮我用完全相同的问题。

溶液:

  1. 转发类本身的定义之前声明友元函数。对于前:

    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

链接导致超时。 – TobiMcNamobi 2017-07-03 08:52:57

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