C++ 泛型编程(二):非类型模板参数,模板特化,模板的分离编译
目錄
- 非類型模板參數(shù)
- 函數(shù)模板的特化
- 類模板的特化
- 全特化
- 偏特化
- 部分參數(shù)特化
- 參數(shù)修飾特化
- 模板分離編譯
- 問題分析
- 解決方法
非類型模板參數(shù)
模板的參數(shù)分為兩種,一種是非類型參數(shù),一種是類型參數(shù)。
類型參數(shù):則是我們通常使用的方式,就是在模板的參數(shù)列表中在class后面加上參數(shù)的類型名稱。
非類型參數(shù):非類型參數(shù)則是用一個常量作為模板的參數(shù),在模板中可以當作常量來使用,通常是需要指明大小或者初始化內(nèi)容的才會用這種。
比較常見的就是c++中的array
array的底層就是直接使用的數(shù)組,而數(shù)組創(chuàng)建時必須指明大小,并且大小得是個常量,所以就會用到非類型模板參數(shù)。
注意:
1. 浮點數(shù)、、自定義類型、類對象以及字符串是不允許作為非類型模板參數(shù)的。
2. 非類型的模板參數(shù)必須在編譯期就能確認結(jié)果。
通常情況下非類型模板參數(shù)都是使用字符型和整型
函數(shù)模板的特化
當我們使用模板來實現(xiàn)一個函數(shù),肯定是想利用它來解決邏輯相同但數(shù)據(jù)類型不同的一些問題,來實現(xiàn)代碼的復(fù)用,但是也存在某些特例,比如針對某一情景或者某一類型,這個模板需要有特殊的處理,這個時候就需要用到模板的特化。
例如:
template<class T> bool IsEqual(T str1, T str2) {return str1 == str2; }int main() {char str1[] = "hello";char str2[] = "hello";if (IsEqual(str1, str2))cout << "true";elsecout << "false"; }
這里不同的原因是傳遞過去的是兩個char*類型,他們兩個比較的不是字符串的內(nèi)容,而是指針的地址,這里str1是在棧上開辟一塊空間后再將hello拷貝過去,而直接傳參的hello則是代碼段中的常量,兩者不可能相同。
如果要比較char*,就得用到strcmp來對這個情況進行特殊處理, 也就是模板的特化。
template<> bool IsEqual<char*>(char* str1, char* str2) {return strcmp(str1, str2) == 0; }函數(shù)模板的特化步驟:
類模板的特化
類也是同理,如果需要有特殊情景也需要特化處理
下面拿這個類舉例子
全特化
全特化即是將模板參數(shù)列表中所有的參數(shù)都確定化。
例如:
這里對test<int,double>版本特化
偏特化
偏特化即是任何針對模版參數(shù)進一步進行條件限制設(shè)計的特化版本
偏特化有兩種表現(xiàn)方式,一種是部分參數(shù)特化,一種是參數(shù)修飾特化
部分參數(shù)特化
這里對第二個參數(shù)特化,只要第二個參數(shù)是double就會調(diào)用對應(yīng)特化版本
template<class T1> class test<T1, double> { public:test(){cout << "test<T1, double>" << endl;}private:T1 _x;double _y; };int main() {test<double, double> t1;test<int, double> t2;test<float, double> t3; }參數(shù)修飾特化
比如用指針或者引用來修飾類型,也可以進行特化
template<class T1, class T2> class test<T1*, T2*> { public:test(){cout << "test<T1*, T2*>" << endl;}private:T1* _x;T2* _y; };int main() {test<double, int> t1;test<int*, double*> t2;test<float*, double*> t3; }模板分離編譯
對于一個代碼量比較多的項目,通常都會采用聲明與定義分離的方法,比如在頭文件進行聲明,在源文件完成代碼的實現(xiàn),最后通過鏈接的方法鏈接成單一的可執(zhí)行文件。但是C++的編譯器卻不支持模板的分離編譯,一旦進行分離編譯,就會出現(xiàn)鏈接錯誤。
問題分析
//頭文件a.h template<class T> bool IsEqual(const T& str1, const T& str2);------------- //源文件a.cpp template<class T> bool IsEqual(const T& str1, const T& str2) {return str1 == str2; } -------------- //test.c #include<iostream> #include"a.h" using namespace std;int main() {cout << IsEqual(3, 5);cout << IsEqual('a', 'b'); }這里看上去是沒有問題的,但是涉及到了模板的實例化規(guī)則。
當主函數(shù)調(diào)用這個函數(shù)的時候他就會去頭文件中找到函數(shù)的聲明,再通過聲明找到a.h中的實現(xiàn)。
但是對于模板卻并不會這樣,因為上一章說過,模板的實例化只會在其第一次使用的時候才會進行,例如這里IsEqual(3, 5),他就會去頭文件中尋找,但是頭文件中只有聲明,沒有定義,無法將其實例化。他又想通過找到a.cpp中的函數(shù)定義來進行實例化,但是遺憾的是,a.cpp中只有IsEqual(const T& str1, const T& str2)的定義,沒有IsEqual(const int & str1, const int T& str2),因為在a.cpp中并沒有使用到該類型的實例,所以自然也不會為其實例化出來,這時test.cpp中就根本無法找到這個函數(shù)的實現(xiàn),就導(dǎo)致了鏈接失敗。
解決方法
這個問題其實沒有什么完美的解決方法
這個問題劉未鵬大佬寫的非常好,可以學(xué)習(xí)一下他的博客
為什么C++編譯器不能支持對模板的分離式編譯
總結(jié)
以上是生活随笔為你收集整理的C++ 泛型编程(二):非类型模板参数,模板特化,模板的分离编译的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: C++ STL : 模拟实现STL中的容
- 下一篇: C++ 面向对象(一)继承:继承、对象切