2014-08-27 52 views
4

Functions.h:的函數模板明確分工導致鏈接錯誤

#pragma once 
#include <iostream> 

template<class T> void TemplatedFunction(T* p) {} 

template<> void TemplatedFunction<float>(float* p) {} 

template<> void TemplatedFunction<char>(char* p) {} 

Functions.cpp:

#include "Functions.h" 

void Test() 
{ 
    TemplatedFunction<float>(NULL); 
    TemplatedFunction<char>(NULL); 
} 

main.cpp中:

#include "Functions.h" 
void Test(); 

int main() 
{ 
    Test(); 
    return 0; 
} 

生成錯誤:

main.obj : error LNK2005: "void __cdecl TemplatedFunction<float>(float *)" ([email protected]@@[email protected]) already defined in Functions.obj 
main.obj : error LNK2005: "void __cdecl TemplatedFunction<char>(char *)" ([email protected]@@[email protected]) already defined in Functions.obj 

我知道兩種方法來解決這個問題:

  1. 不包括Functions.h幾個.cpp文件 - 不能在複雜的工程應用,如果H-文件包含許多需要一些額外的定義。 cpp文件。

  2. 聲明所有模板函數爲static。但是這意味着特定的函數會出現在包含Functions.h的所有.cpp文件中,即使它們未被使用,這可能會導致代碼重複。

所以,我看到專門的模板功能就像非模板化功能一樣。如果沒有static聲明,是否有其他解決方案來防止鏈接器錯誤?如果函數聲明爲static,現代C++編譯器是否將它們從優化構建中刪除,如果它們未被使用?

編輯。 閱讀前兩個答案後:我不問在這裏如何防止此類鏈接器錯誤。假設我不能將專業化移動到.cpp文件並將其保留在012h或inline的.h文件中,這是否會導致代碼複製和優化版本中的膨脹,當這些函數被添加到包含.h文件的每個.cpp文件時,即使他們沒有使用?

+4

顯式特化的主體需要像普通的非模板函數一樣進入cpp文件(這就是它們)。如果你願意(或者有意義),你可以用'inline'交替標記它們。 – dlf 2014-08-27 14:30:58

回答

11

所以,我看到專門的模板函數的行爲像非模板化函數。

正確。

是否有任何其他解決方案,以防止鏈接器錯誤沒有static聲明?

是,像任何正常的非模板函數:

要麼定義功能特化作爲inline

申報(但不限定)標頭中的專業:

template<> void TemplatedFunction<float>(float* p); 

template<> void TemplatedFunction<char>(char* p); 

並在Functions.cpp中定義它們

template<> void TemplatedFunction<float>(float* p) {} 

template<> void TemplatedFunction<char>(char* p) {} 

它們比使用static更好的選擇,因爲製作的功能的靜態還有其他副作用,如給予的功能不同的地址,在每個翻譯單元,並使得在每一個翻譯單元不同的局部靜態變量。這是一種語義變化,而不僅僅是鏈接器錯誤的解決方案。

如果函數聲明爲static,現代C++編譯器是否將它們從優化構建中刪除,如果它們未被使用?

是的。但是,在使用它們的任何文件中,您將得到重複的代碼,使得可執行文件比僅有函數的單個定義更大。

假設我不能動專業化.cpp文件,並把它與static .h文件中...

我看不到任何好的理由爲什麼這樣做是必要的,但無論如何, ...

...或inline,確實在優化的建立這項事業代碼重複和腹脹,當這些功能被加入到其中包含的.h文件中的每個.cpp文件,即使不使用他們?

不,如果它們不在給定文件中使用,它們不會影響從該文件編譯的對象的大小。

你的問題很容易讓人誤解,因爲它似乎是關於模板的(關於模板的標題非常清楚!),但是未使用的內聯/靜態函數是否導致代碼膨脹與函數是否是模板無關。

如果你的問題只是「做未使用的內聯函數和靜態函數會影響對象大小嗎?」對於普通功能和功能模板,答案都是否定的。

+0

謝謝,但我的問題的主要觀點是:如果函數保留在.h文件中,是否會導致代碼在優化構建中膨脹?看到我編輯的問題。 – 2014-08-27 14:55:08

+0

答覆已更新。 – 2014-08-27 15:03:14

2

這種明確的專業化應該移動到.cpp文件或製作inline。鏈接器會在那裏找到它們。如果你在頭文件中定義它們,你會得到「已經定義」的錯誤信息,就像你在多個編譯單元包含的頭文件中定義的普通非內聯和非靜態函數一樣。

+0

謝謝,但我的問題的主要觀點是:如果函數保留在.h文件中,是否會導致代碼在優化構建中膨脹?看到我編輯的問題。 – 2014-08-27 14:54:45

+1

如果您將它們設爲'inline',請將這些專業化看作普通的內聯函數。通常它們不應該導致任何代碼膨脹,但是 - 與常規內聯一樣 - 有時可能值得檢查並且例如將它們臨時插入到.cpp中並比較可執行文件的大小。 – 2014-08-27 14:57:11

+0

謝謝,比較可執行文件的大小是個好主意,我會這樣做。 – 2014-08-27 14:59:18