1. 程式人生 > >C++踩坑-模板類

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跨檔案標記出需要的例項化,從而編譯時就能解決這個問題了。