函式模板提倡直接定義 而非申明 在 h檔案裡,為什麼不用擔心 h被包含後出現重定義錯誤?

時間 2021-05-30 00:12:08

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 ...