在編譯模板的時候,編譯器會分兩個階段去解析遇到的名稱,第一個階段解析不依賴於模板參數的名稱,第二個階段解析依賴於模板參數的名稱,下面舉個簡單的例子來說明這一點:
template這個例子中定義了兩個類模板,其中Y派生於X,在X中我們給int取了個別名E,接著在全局作用域中給double也取了個別名E,在Y中有一個函數f(),它的返回值類型為E,那麼這個E到底是double呢,還是int?結果是double,因為f()不依賴與模板參數T,所以它在第一階段就會被解析,而它的基類X<.T>在第二階段才會被解析,所以解析f()的時候只能看到全局作用域裡的typedef double E。如果大家心裡有疑問,我們可以看看非模板類的情況:class X { public: typedef int E; }; typedef double E; template class Y : public X { public: E f() {} };
class X { public: typedef int E; }; typedef double E; class Y : public X { public: E f() {} }; int main(){ Y y; cout<這個例子中都是普通的類,通過main函數的測試,可以看到f()的返回類型變成了int。接下來我們再來看一個例子: void g() { cout<<"gobal::g()"<class X { public: typedef int E; void g() { cout<<"X::g()"< class Y : public X { public: E f() { g(); this->g(); } }; int main(){ Y y; cout< 這個例子中首先定義了一個全局函數g(),接著定義了類模板X,在X中定義了一個成員函數g(),類模板Y依然繼承於X,在Y中的f()中“以兩種方式”調用了g(),那麼這兩種方式調用的是同一個g()嗎?答案是:不是,第一種方式調用了全局的g(),而第二種方式調用了基類的g(),原因在於當編譯器遇到第一種方式的g()時,發現它沒有表現出要依賴於模板參數,所以認為它不依賴於模板參數,因而在第一階段就進行了解析,此時X 尚未解析,所以g()是全局的g(),通過第二種方式調用時,用this指針指出g()是依賴於當前對象的,也就依賴於模板參數,因而會在第二階段解析,那時基類也會先於Y進行了解析,所以this-->g()調用了基類的g()。同樣,我們可以看看普通類的情況: void g() { cout<<"gobal::g()"<class X { public: typedef int E; void g() { cout<<"X::g()"< class Y : public X { public: E f() { g(); this->g(); } }; int main(){ Y y; cout< 結果會發現,兩次都調用了基類X的g(),這個例子告訴我們,在類模板中,如果需要使用成員函數,需要通過this指針來指定,而不能像在普通類中那樣省略到this指針,事實上,如果不用this指針來指定,而又沒有全局函數g(),編譯時會出現如下錯誤:
error:there are no arguments to 'g' that depend on a template parameter, so a declaration of 'g' must be available.