2010-09-13 198 views
12

我想通了顯式實例請求將自動實例的所有基類成員還可以,但使用Visual Studio 2008或2010顯式實例化C++類模板實例化相關基類?

注意添加到foo()bar()呼叫強制編譯器建設這個代碼時,我得到一個linker error: unresolved external symbol "public: void Base<int>::foo(int)"實例化Base<int>::bar()並且構建成功,所以似乎編譯器具有實例化foo()所需的全部信息。

明顯地,在source.cpp中明確實例化Base<int>可以使構建成功,但顯式實例化派生類時需要顯式實例化任何相關基類似乎很愚蠢。

這是正常的嗎?我無法找到關於這個問題的標準。

header.h

template<typename T> 
class Base { 
public: 
    void foo(); 
}; 

template<typename T> 
class Derived : public Base<T> { 
public: 
    void bar(); 
}; 

source.cpp

#include "header.h" 

template<typename T> 
void Base<T>::foo() { } 

template<typename T> 
void Derived<T>::bar() { 
    // this->foo(); // adding this forces instantiation of foo()??? 
} 

template class Derived<int>; 

的main.cpp

#include "header.h" 

int main() { 
    Derived<int> d; 
    d.foo(); // Linker Error: unresolved external symbol "public: void Base<int>::foo(int)" 
} 

編輯:

它看起來像標準說只有一個類的成員通過顯式類實例化來實例化,所以在我的例子中鏈接器錯誤是合理的。

請注意,一個類是由class-head {member-specification}定義的,「類定義中的成員規範聲明瞭該類的全部成員;沒有成員可以添加到別處。因此,成員只在大括號{}之間,並且公共基類成員不會成爲派生類的成員,它們只能從派生類或派生類的對象訪問。

我唯一剩下的問題是爲什麼標準指定類模板的顯式實例化只實例化成員而不是基類的成員?我的猜測是,這可以更好地控制哪些地方顯式實例化。某個使用顯式模板類實例的人很可能將基類定義放在與派生類定義不同的文件中,並且會分別明確地實例化每個實例。

+0

是否爲基類的派生觸發器實例化添加顯式構造函數?我懷疑編譯器正在嘗試不做更多的工作。有一個構造函數可能會讓它意識到它需要構建Base,並且可能會觸發它。另外,你有沒有嘗試gcc或其他編譯器? – 2010-09-15 00:00:41

+0

添加一個帶或不帶參數且帶或不帶關鍵字「explicit」的構造函數都不會觸發基類foo()的實例化,但是從派生成員bar()調用foo()會觸發隱式實例化。 – JohnPS 2010-09-15 00:54:54

回答

9

標準說

類模板專業化的顯式實例意味着其所有成員之前沒有明確的專業包含顯式實例翻譯單元的的實例。

換句話說,它沒有要求基類被輪流實例化。它會導致它們的隱式實例化,而不會實例化它們的成員定義。這是標準中的一個醜陋的小故障,它是指一些文本中「成員」是指「直接」還是「繼承」的成員,因爲對於編寫標準措辭的人來說,這似乎是「顯而易見的」,但對於一個誰讀它。 C++ 0x增加了一些說明(C++ 03沒有明確實例化聲明定義之間的差異,但即使忽略這一點,C++ 0x的措辭包含一些更多的位洞察力):

的顯式實例名稱類模板特殊化也是它的每個成員(不包括成員從基本繼承 類),其具有的 同類(聲明或者去網絡nition)的顯式實例先前未明確專門用於包含明確的示例的翻譯單元,除了下面描述的內容之外。 [注意:另外,它通常是一個明確的實例化 某些與實現有關的類的數據。 - 結束註釋]

+0

+1。是否沒有更廣泛的一攬子聲明,例如它與類的定義/聲明及其所有靜態成員沒有區別?無論vtable是否被實例化,都保持開放,這是他們所承認的醜陋。 – Potatoswatter 2010-09-14 20:00:32

+1

+1本標準使用「類模板專業化」來定義由「顯式實例化」與「顯式專業化」使用模板<>生成的實體。我想沒有實例化基礎成員允許更多的控制什麼得到實例化和它去哪裏。基本成員可以在與派生類不同的源文件中實例化。 – JohnPS 2010-09-14 23:58:40

+0

@Patatoswatter:我們不僅需要基類的聲明來確定派生類的實例化過程中派生類的vtable的大小,並且它的vtable中的值是由鏈接器填充的嗎?如果任何調用的函數未在某些翻譯單元中實例化,則會出現鏈接器錯誤。 – JohnPS 2010-09-15 00:41:23