2010-10-25 88 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); } 
};