2010-03-30 68 views
5

在使用模板函數之前,不會編譯模板代碼。但是,它在哪裏保存了編譯後的代碼,它是否保存在首先使用模板函數的目標文件中?在C++中理解模板的問題

例如, main.cpp中是調用從文件test.h模板函數,編譯器生成的目標文件main.o, 是對main.o文件內的模板函數?因爲模板代碼沒有內聯,是嗎?

+0

是什麼讓你認爲模板代碼沒有內聯?嘗試編譯一個啓用了優化的簡單示例,然後反彙編結果。 – 2010-03-30 14:03:05

回答

4

它完全依賴於編譯器實現。大多數編譯器會生成代碼,內聯或類似cpp的文件,然後編譯。有時候,通過優化設置,一些編譯器甚至會重複使用相同的代碼,而不是爲每個cpp重新創建它。

所以你必須看到你的編譯器的文檔的更多細節。

+3

這是實際的正確答案,而不是OP所接受的答案。 – 2010-03-30 17:09:04

0

它總是內聯的(意思是說,它總是內聯,有內聯語義)。實際上,它可能不是內聯的,就像內聯函數一樣,但是,模板不是代碼。這是一個「製作代碼的模板」。因此,它通常會駐留在標題中,除特殊情況外,請參見下文。

有一個想法可以做別的,代號爲「export keyword」。它被從標準中刪除。

特殊情況:您可以將模板實例化編譯爲目標文件,而無需使用它們。這是避免內嵌所有模板代碼的唯一方法。 這是它是如何做:

template class std::vector<MyClass>; 

這將迫使編譯器在當前位置來實例化一個模板。的C++ 0x將有一個語法強制編譯做到這一點,並有其他地方的模板實例鏈接搜索:

extern template class std::vector<MyClass>; // C++0x only

+4

它不是內聯的,必然。它在編譯單元中實例化,可以內聯但不可以。 – 2010-03-30 14:00:21

+1

export關鍵字與內聯無關,而是以編譯後的形式提供模板以供客戶端代碼稍後實例化。 – 2010-03-30 17:11:37

0

你的意思是實例,而不是編譯。在編譯時,編譯器會找出您的代碼使用並安裝(在對象文件中)所有必需版本的每個版本。

3

是的,模板功能代碼在main.o文件中發出。其中一些可以內聯,因爲可以內聯任何其他代碼,但是通常,模板的代碼在任何文件中發出,其中模板是實例化的。可以認爲它是首先實例化模板代碼以生成正常的非模板函數,然後使用編譯器應用於任何其他函數的任何內聯和優化來編譯這些函數。

當在多個編譯單元(.cpp文件)中出現相同的模板實例(例如std::vector<int>)時,會有一點困難,因爲代碼在每個編譯單元中都被實例化。有多種處理方法,有時涉及鏈接階段的清理步驟,其中重複的模板實例解析爲單個實例;你的編譯器手冊可以提供更多關於它如何處理這種情況的信息。

+0

所以創建一個帶有未使用的虛擬變量的模板類與創建類並將所有內容放在頭文件中並不相同。後者將內聯,模板類取決於編譯器如何處理它? – hidayat 2010-03-30 14:08:11

+0

@ hidayat:不可以。同樣的規則適用於「正常」類和類模板。 – 2010-03-30 14:15:34

+0

重複:我認爲這是目標文件格式的標準功能,可以在鏈接時組合一段。我覺得* *至少有一個系統叫他們'COMDAT'部分:http://docsun.cites.uiuc.edu/sun_docs/C/solaris_9/SUNWdev/LLM/p44.html(IIRC一些連接甚至會檢查節是相同的,以避免一些錯誤。) – BCS 2010-03-30 15:45:01

1

模板代碼編譯即使它從未實例化。否則,不能要求編譯器發出診斷爲這樣:

template< typename T > 
void f() 
{ 
    blah 
} 

模板編譯發生在兩個階段。除了基本檢查之外,只有在實例化模板並使用實際類型填充形式參數時才能檢查依賴於模板參數的所有內容。例如,這裏

template< typename T > 
void f() 
{ 
    typename T::nested_type x; 
} 

T::nested_type只能在模板實例化後檢查和實際類型,給出了T。但是,在編譯器遇到模板定義時執行基本檢查(「T::nested_type是一種類型,是否爲有效的變量定義?」)。 (這就是爲什麼typename是必需的,順便說一下,根據T,T::nested_type可能只是T成員的名字或靜態數據成員 - 這會使得T::nested_type x;出現語法錯誤,所以我們必須告訴編譯器將T::nested_type作爲一種類型的名稱)。