2010-02-19 64 views
2

考慮下面的例子:爲什麼對模板化基類的函數調用不起作用?

template <typename T> 
class A { 
    public: 
     void f() { 
      cout << "A::f()\n"; 
     } 
}; 

template<> 
class A<int> { 
}; 

template<typename T> 
class B: public A<T> { 
    public: 
     void g() { 
      cout << "B::g()\n"; 
      A<T>::f(); 
     } 
}; 

int main() { 
    B<int> b;  // (1) 
    b.g();  // (2) 

    return 0; 
} 

顯然調用內部B ::克A :: f()的()將對於int模板類型失敗。我的問題是電話在什麼時候失敗?在(1)或(2)?我認爲它應該是(1),因爲那時編譯器會創建一個新的類,其中的模板類型爲int並編譯它。該編譯應該在f()中失敗是正確的?

+0

什麼是main()的輸出? – John 2010-02-19 21:04:45

+1

@John:沒有,因爲編譯會失敗。 – 2010-02-19 21:08:48

+0

哦,好的。我很困惑,因爲你在談論「在什麼時候調用失敗」 - 並且在代碼中評論了點 - 就好像它已經編譯一樣。 – John 2010-02-19 21:41:04

回答

3

它在2)失敗。模板的成員函數在被調用時被實例化。

更確切地說:當一個類模板被實例化時,其成員函數的聲明就被實例化了,但是它們的定義並沒有被實例化。該定義在使用該功能時被實例化。

+0

一個有趣的事實是,如果你從那個TU中的所有模板定義或者'A'的顯式特化中刪除了函數'f',那麼編譯器被允許標記成員函數'g'的定義不合格並且發出一個即使「B」從未使用過,因爲對於該成員函數('14.7/8')永遠不會生成有效的特化。 – 2010-02-20 17:51:56

4

它會在(2)失敗,這是由標準保證。在第14.7.1/1節中,它說實例化一個模板類而不是實例化它的成員定義。這隻會在會員使用後纔會發生。

如果從代碼中刪除(2),它將被編譯。

14.7.1/1摘錄:
類模板專業化的隱式實例使隱 實例化的聲明,但不定義或默認參數,的類的成員函數,構件類,靜態數據成員和成員模板;它會導致成員匿名聯合定義的隱式實例化。

強調我的。


Visual Studio的診斷具有誤導性。它會說see reference to class template instantiation 'B<T>' being compiled。這意味着不是「我在B<T>的實例化失敗」,但「我沒有在實例化類的成員B<T>

+1

最好的事情是VC只指向實例化'B'的那一行。無論如何,我現在應該已經學會了對VC的懷疑,並且只是先查找它。 – 2010-02-19 21:24:38

相關問題