2 回答

TA貢獻1840條經驗 獲得超5個贊
C ++答案(一般答案)
考慮一個Derived
帶有模板基類的模板類:
template <typename T>class Base {public: int d;};template <typename T>class Derived : public Base<T> { void f () { this->d = 0; }};
this
有類型Derived<T>
,依賴的類型T
。所以this
有依賴類型。所以this->d
做d
一個從屬名稱。在模板定義的上下文中查找從屬名稱作為非依賴名稱并在實例化的上下文中查找。
沒有this->
,名稱d
只會被查找為非依賴名稱,而不能找到。
另一種解決方案是d
在模板定義中聲明:
template <typename T>class Derived : public Base<T> { using Base::d; void f () { d = 0; }};
Qanswer(具體答案)
d
是...的成員QScopedPointer
。它不是一個繼承的成員。this->
這里沒有必要。
OTOH QScopedArrayPointer
是一個模板類,d
是模板基類的繼承成員:
template <typename T, typename Cleanup = QScopedPointerArrayDeleter<T> >class QScopedArrayPointer : public QScopedPointer<T, Cleanup>
所以這里this->
是必要的:
inline T &operator[](int i){ return this->d[i];}
很容易看出,放在this->
任何地方都比較容易。
了解原因
我想所有C ++用戶都不清楚為什么在非依賴基類中查找名稱而在依賴基類中查找名稱:
class Base0 {public: int nd;};template <typename T>class Derived2 : public Base0, // non-dependent base public Base<T> { // dependent base void f () { nd; // Base0::b d; // lookup of "d" finds nothing f (this); // lookup of "f" finds nothing // will find "f" later }};
“標準如此說”旁邊有一個原因:模板中名稱綁定的方式起作用。
在模板實例化時,模板可以具有后期綁定的名稱:例如,f
在f (this)
。在Derived2::f()
定義時,f
編譯器不知道變量,函數或類型名稱。此時f
可以引用的已知實體集是空的。這不是問題,因為編譯器知道它f
稍后將作為函數名稱或模板函數名稱進行查找。
OTOH,編譯器不知道該怎么做d
; 它不是(稱為)函數名稱。無法對非(調用)函數名稱進行后期綁定。
現在,所有這些看起來都像編譯時模板多態的基本知識。真正的問題似乎是:為什么不是d
必然要Base<T>::d
在模板定義的時間?
真正的問題是Base<T>::d
在模板定義時沒有,因為那時沒有完整的類型Base<T>
:Base<T>
聲明,但沒有定義!你可能會問:這是怎么回事:
template <typename T>class Base {public: int d;};
它看起來像一個完整類型的定義!
實際上,直到實例化,它看起來更像是:
template <typename T>class Base;
到編譯器。無法在類模板中查找名稱!但僅限于模板特化(實例化)。模板是一個工廠,使模板專業化,模板不是一組模板專業化。編譯器可以查找d
在Base<T>
任何特定類型T
,但它無法查找d
在類模板Base
。在T
確定類型之前,Base<T>::d
仍然是抽象的Base<T>::d
; 只有當類型T
已知時,才Base<T>::d
開始引用類型的變量int
。
這樣做的結果是類模板 Derived2
具有完整的基類,Base0
但是具有不完整的(前向聲明的)基類Base
。僅對于已知類型T
,“模板類”(類模板的特化)Derived2<T>
具有完整的基類,就像任何普通類一樣。
你現在看到:
template <typename T>class Derived : public Base<T>
實際上是一個基類規范模板(一個制作基類規范的工廠),它遵循模板內基類規范的不同規則。
備注:讀者可能已經注意到我在解釋結束時編寫了一些短語。
這是非常不同的:這里d
是一個限定名稱Derived<T>
,Derived<T>
因為它T
是一個模板參數。即使不是(稱為)函數名,限定名也可以延遲綁定。
另一個解決方案是:
template <typename T>class Derived : public Base<T> { void f () { Derived::d = 0; // qualified name }};
這是等效的。
如果你認為在定義里面Derived<T>
,Derived<T>
作為一個已知的完整類的處理有時和作為一個未知的類在其他時候不一致,那么,你是對的。

TA貢獻1744條經驗 獲得超4個贊
我猜它應該與Cleanup()例程的重載使用有關。傳遞的類型由模板類型T顯式控制,而模板類型T又可以控制調用哪個重載版本的Cleanup()。
- 2 回答
- 0 關注
- 636 瀏覽
添加回答
舉報