2011-07-04 53 views
15

這一次編譯和工作像它應該(非嵌套模板):運營商<<(ostream的和,X)類X嵌套在一個類模板

#include <iostream> 

template<typename T> class Z; 

template <typename T> 
std::ostream& operator<< (std::ostream& os, const Z<T>&) { 
    return (os << "Z"); 
} 

template<typename T> class Z { 
    friend std::ostream& operator<< <> (std::ostream& os, const Z&); 
}; 

int main() { 
    Z<int> z; 
    std::cout << z << std::endl; 
} 

這一個不編譯器(gcc 4.4和GCC 4.6,在03和0X模式):

#include <iostream> 

template<typename T> class Z; 

template<typename T> 
std::ostream& operator<< (std::ostream& os, const typename Z<T>::ZZ&) { 
    return (os << "ZZ!"); 
} 

template <typename T> class Z { 
    public: 
    class ZZ { 
     friend std::ostream& operator<< <> (std::ostream& os, const ZZ&); 
    }; 
}; 


int main() { 
    Z<int>::ZZ zz; 
    std::cout << zz << std::endl; 
} 

錯誤信息是這樣的:

error: template-id ‘operator<< <>’ for ‘std::ostream& operator<<(std::ostream&, 
const Z<int>::ZZ&)’ does not match any template declaration 
error: no match for ‘operator<<’ in ‘std::cout << zz’ 

在0X模式的第二個錯誤我ssage是不同的,但意義是相同的。

是否可以做我想做的事情?

編輯顯然,有非推斷上下文這裏,這說明了錯誤信息的一個實例。但是,這個問題仍然存在:對於嵌套在類模板中的類,我可以使用operator<<嗎?

+0

我正在處理它......第一個錯誤是通過放置「operator << 」,這也使事情變得更加可讀。 – AudioDroid

+0

可能的重複[如何從C++模板中的方法類型推導出類的類型?](http://stackoverflow.com/questions/3830491/how-to-deduce-class-type-from-method-type-in​​-c -templates) –

+0

@Matthieu:我很希望看到來自該鏈接的代碼適應了這個問題。我可以把這個答案作爲像我這樣的「普通凡人」的答案嗎(可能是「n.m.」)嗎? ;-) – AudioDroid

回答

3

馬修解釋這個問題非常好,但一個簡單的工作可以在這種情況下使用。 您可以實現友元函數與友元聲明的類中:

#include <iostream> 

template <typename T> class Z { 
public: 
    class ZZ { 
    friend std::ostream& operator<< (std::ostream& os, const ZZ&) { 
     return os << "ZZ!"; 
    } 
    }; 
}; 


int main() { 
    Z<int>::ZZ zz; 
    std::cout << zz << std::endl; 
} 
+0

謝謝!你讓我今天很開心。 – niklasfi

4

除此之外朋友聲明不匹配操作模板(也許可以解決的)

class ZZ { 
    template<class U> 
    friend std::ostream& operator<<(std::ostream& os, const ZZ&); 
}; 

你也有一個「非推論語境」,這是什麼馬修鏈接的問題時,至。

在此模板

template<typename T> 
std::ostream& operator<< (std::ostream& os, const typename Z<T>::ZZ&) { 
    return (os << "ZZ!"); 
} 

編譯器無法弄清楚什麼T的你參數匹配。可能有幾場比賽,如果你專注於某些類型的

template<> 
class Z<long> 
{ 
public: 
    typedef double ZZ; 
}; 

template<> 
class Z<bool> 
{ 
public: 
    typedef double ZZ; 
}; 

現在,如果我嘗試打印doubleT可能是要麼boollong

編譯器無法確切地知道這一點,沒有檢查全部可能的T,它不必這樣做。它只是跳過你的運營商。

+0

有沒有辦法解決這個問題?我可以在friend聲明中定義'operator <<'內嵌的權限,並且一切似乎都有效。但是如果我因爲某種原因不喜歡內聯定義,還有其他方法嗎? –

+0

@ n.m。 - 我不認爲有更好的方法。如果您在每個班級中定義了操作員,您將解決任何可能的專業化問題。無論我們喜不喜歡,模板都只有內聯函數的頭文件。 :-( –

7

這是功能的一個普遍問題:

template <typename C> 
void func(typename C::iterator i); 

現在,如果我叫func(int*),我應該使用哪一種C價值?

一般來說,你不能工作落後!許多不同的C可能已經定義了內部類型iterator,對於某些參數集恰好是int*

在你的情況,你是有點複雜的情況:

template <typename T> 
void func(typename Z<T>::ZZ const&); 

但從根本上講,這是同一個問題,Z<T>是一個模板,而不是一個完整的類,以及你所要求創建一個功能此模板的內部類型ZZ

想我做的事:

template <typename T> 
struct Z { typedef T ZZ; }; 

template <typename T> 
struct Z<T const> { typedef T ZZ; }; 

注:典型的迭代器,該value_type不是常量限定

然後,調用func(int)的時候,我應該使用Z<int>Z<int const>

這是不可扣除的。

因此,整個事情被稱爲不可扣除的上下文,標準禁止它,因爲沒有明智的答案。

經驗法則:在函數的參數中可疑typename

注:它們是確定的,如果換個說法已經固定下來的類型,例如typename C::iterator find(C&, typename C::const_reference);因爲一旦C推導,然後C::const_reference可無故障使用

+1

所以有什麼解決方法嗎?我想'operator <<'爲我的嵌套類,有沒有一種方法來定義它?除了直接在朋友聲明中直接定義它 –

+1

@nm:不,沒有,只要該類仍然嵌套。一個選項是定義模板'Z'外的類(例如在'details'命名空間中),並在'operator <<'旁邊,然後在'Z'內使用'typedef'。 –

+0

@Matthieu選項將依賴於CRTP。請參閱我的答案以獲得解釋。這不如朋友的方式,但如果一個人不能使用它,可以試試:) –

2

不同的技術是提供一種脫節類模板,像一個鉤子。

template <typename T> class ZZZ { 
    T &getDerived() { return static_cast<T&>(*this); } 
    T const &getDerived() const { return static_cast<T const&>(*this); } 

protected: 
    ~ZZZ() { } 
}; 

template <typename T> class Z { 
    public: 
    class ZZ : public ZZZ<ZZ> { 
    }; 
}; 

template<typename ZZ> 
std::ostream& operator<< (std::ostream& os, const ZZZ<ZZ> &zzz) { 
    ZZ const& zz = zzz.getDerived(); 
    /* now you can use zz */ 
    return (os << "ZZ!"); 
} 

雖然使用朋友函數定義是可取的。但是瞭解替代品是很好的。

+0

不錯的把戲,更通用和很好迴避範圍泄漏我有:) –

+0

謝謝。一個很好的伎倆! –