C++踩坑-模板類
關於template<>只能定義在.h檔案中:
在學習資料結構C++實現的時候,踩中了C++的一個坑,如下:
/*<function.h>*/ template <typename st, typename k> class Search{ public: void search(st t, k num)//模板類函式只能定義於此 { tar = t; key = num; } int Bisearch() { int low = 1; int high = tar.length; int mid; while (low < high) { mid = (low + high) / 2; if (tar.elem[mid] == key) return mid; else if (tar.elem[mid] < key) low = mid; else high = mid; } return -1; } private: st tar; k key; };
模板類Search的成員函式只能定義在.h檔案中,無法在.cpp檔案中定義,定義則會報錯:
error LNK2019: 無法解析的外部符號 "public: int __thiscall Search<struct SSTable,int>::Bisearch(void)" ([email protected][email protected]@@[email protected]@QAEHXZ),該符號在函式 _main 中被引用
這個問題是關於模版類的成員函式的定義方法的問題。我按照普通類的寫法,在function.h中宣告類的成員函式,在function.cpp中寫該函式的定義,然後在main.cpp中include<function.h>檔案,編譯時把main.cpp和function.cpp放在同一個編譯單元裡面。按理這樣就能生成可執行檔案了,但是連結時卻報以上錯誤。
原因是模版類在編譯時是在使用的地方才例項化,但不同的.cpp檔案是在link時才相互關聯,因此編譯main.cpp時只例項化了函式的宣告,並且認為在某個地方已經例項化了函式的定義,悲劇的是編譯function.cpp時並沒有給main.cpp中的這個用法做例項化,於是linker就找不到main.cpp所需要的函式定義了。
於是只有兩種解決辦法,或者在function.cpp中給需要的例項化顯示地做定義(這樣做擴充套件性就很差),或者把template函式的定義也放在.h檔案中。
轉帖討論了更加深入的解決方案,複製如下:
於是我和@吳磊達人討論為什麼C++沒辦法直接在編譯時跨檔案例項化template,結論是源於C的單檔案編譯單元的效率考慮,使得編譯時(連結之前)是沒辦法知道其他編譯單元到底需要什麼例項。如果linker能給compiler反饋機制,使得linker之後還能再編譯一遍給做必要的例項化,應該能提供這個特性(填上這個反直覺的坑)了,或者在編譯之前專門做一遍預編譯,給每個使用的template跨檔案標記出需要的例項化,從而編譯時就能解決這個問題了。