1樓:熊起
這事兒有的操心,因為編譯器只保證你若都寫.h裡, 行為可以一致, 如果在不同CPP裡搞幾份不一樣的同宣告模板函式, 可能就選了唯一的某個版本.
剛用VC2019測了一下:
testfoo.cpp
template
int testfoo(T)
return sizeof(T)+11;
int externfoo()
return testfoo(0);
main.cpp:
template
int testfoo(T)
return sizeof(T);
int externfoo();
int main(int argc, char* argv)return externfoo() + testfoo(0);
結果返回30.
這說明main.cpp裡的testfoo被替換成了testfoo.cpp裡的testfoo, 連個警告都沒有的.
2樓:
不是說倡議定義在標頭檔案裡,而是說要是你不把這個模板定義在標頭檔案裡,其他要用這個模板的編譯單元,由於不知道這個模板的實現,就沒法進行例項化。(除非 C++11 以後,你用了 extern template,明確告知編譯器,使用了某一組引數的模板已經例項化)
extern template 例子:
// a.cpp
template
void f(const T&);
extern template void f(const int&); // 明確告知編譯器 f(const int&) 已經在其他編譯單元裡例項化了。
template
class Foo;
extern template class Foo; // 明確告知編譯器Foo 已經在其他編譯單元裡例項化了。
注意其他答主說的「必須定義在標頭檔案裡」,回答的就太籠統了,嚴格來說並不對。比如在原始檔 .cpp 裡頭寫模板也並無問題啊,只要這個模板只在這個檔案裡才被使用就好了。
另外,extern template,也不需要你提供模板的實現,只要求有模板的原型宣告就好了。
至於題主懷疑的「是否會產生重定義的錯誤」,大可放心,因為 C++ 標準明確規定了,對於相同的模板例項,編譯器可以隨機選擇乙份留下來,其餘的都丟棄掉。因此不會發生重定義的問題。
3樓:d41d8c
簡而言之,因為 [basic.def.odr] 是這麼規定的。
不過限制很多而且複雜。如果有可能的話,個人更提倡定義在模組(module)裡,這樣就不需要也不允許重複定義了。
另見為什麼c++模板類不存在單定義問題?
4樓:杜紫童
並不是提倡,而是只能寫到頭檔案裡。除非你在用到的 cpp 檔案裡再單獨寫一次定義。
當然,既然是寫在標頭檔案裡,肯定會導致重定義錯誤。
解決重定義錯誤的唯一方法是:inline!
PS,C++的inline跟C的inline是兩個完全不同的東西。
也許你發現很多模板並沒有宣告為inline也能正常編譯,那是因為類的成員函式預設是inline的。
5樓:念雪到天明
因為編譯器遇到函式才會真正例項化,你如果不定義在標頭檔案裡,編譯器就不會例項化。那你就必須把模板定義寫在某個cpp裡,同時還必須有宣告,否則還是不會例項化。就算你在某個cpp裡面宣告了,真的例項化了,那你還得麻煩鏈結器把位址鏈結在一起,多麻煩。
如果害怕可以加inline。
說了半天我也不知道自己說了點啥,可參考C++primer第16章。
函式模板中const string 型別的形參為什麼不能傳入C風格字串 ?
杜紫童 你誤解了模板的用法,不是你寫了特化就一定會使用特化版本。當你使用原生字串的時候,模板引數T是const char 呼叫的是chen add而不是chen add。 Muchan 模板引數推導發生在過載決議之前。編譯add hello my laddy 時,根據第乙個引數推導T const c...
為什麼c 沒有使用函式模板過載qsort等函式,是因為沒有必要嗎?
暮無井見鈴 C 有 sort 其實標準紙面上 qsort 有過載,不過不是函式模板,而實現上 給 qsort 新增過載看起來沒有什麼方便的。C 增加 C 標準庫函式的過載主要就幾個模式 部分 str wcs mem 系列函式增加過載,為了 const 正確性 大多數數學函式為各種算術型別提供過載,而...
請問c 模板函式如何限定引數型別?
Lee Revere template T void test T t requires std is same v std is same v std is same v std is same v 或者concept namespace detail template VALID T void ...