您好,登錄后才能下訂單哦!
1.模板特化
1.1概述
模板特化(template specialization)不同于模板的實例化,模板參數在某種特定類型下的具體實現稱為模板的特化。模板特化有時也稱之為模板的具體化,分別有函數模板特化和類模板特化。
1.2函數模板特化
函數模板特化是在一個統一的函數模板不能在所有類型實例下正常工作時,需要定義類型參數在實例化為特定類型時函數模板的特定實現版本。查看如下例子。
#include <iostream> using namespace std; template<typename T> T Max(T t1,T t2) { return (t1>t2)?t1:t2; } typedef const char* CCP; template<> CCP Max<CCP>(CCP s1,CCP s2) { return (strcmp(s1,s2)>0)?s1:s2; } int main() { //調用實例:int Max<int>(int,int) int i=Max(10,5); //調用顯示特化:const char* Max<const char*>(const char*,const char*) const char* p=Max<const char*>("very","good"); cout<<"i:"<<i<<endl; cout<<"p:"<<p<<endl; }
程序正常編譯運行結果:
i:10
p:very
在函數模板顯示特化定義(Explicit Specialization Definition)中,顯示關鍵字template和一對尖括號<>,然后是函數模板特化的定義。該定義指出了模板名、被用來特化模板的模板實參,以及函數參數表和函數體。在上面的程序中,如果不給出函數模板Max< T>在T為const char*時的特化版本,那么在比較兩個字符串的大小時,比較的是字符串的起始地址的大小,而不是字符串的內容在字典序中先后次序。
除了定義函數模板特化版本外,還可以直接給出模板函數在特定類型下的重載形式(普通函數)。使用函數重載可以實現函數模板特化的功能,也可以避免函數模板的特定實例的失效。例如,把上面的模板特化可以改成如下重載函數。
typedef const char* CCP; CCP Max(CCP s1,CCP s2) { return (strcmp(s1,s2)>0)?s1:s2; }
程序運行結果和使用函數模板特化相同。但是,使用普通函數重載和使用模板特化還是有不同之處,主要表現在如下兩個方面:
(1)如果使用普通重載函數,那么不管是否發生實際的函數調用,都會在目標文件中生成該函數的二進制代碼。而如果使用模板的特化版本,除非發生函數調用,否則不會在目標文件中包含特化模板函數的二進制代碼。這符合函數模板的“惰性實例化”準則。
(2)如果使用普通重載函數,那么在分離編譯模式下,應該在各個源文件中包含重載函數的申明,否則在某些源文件中就會使用模板函數,而不是重載函數。
1.3類模板特化
類模板特化類似于函數模板的特化,即類模板參數在某種特定類型下的具體實現。考察如下代碼。
#include <iostream> using namespace std; template<typename T>class A { T num; public: A() { num=T(6.6); } void print() { cout<<"A'num:"<<num<<endl; } }; template<> class A<char*> { char* str; public: A(){ str="A' special definition "; } void print(){ cout<<str<<endl; } }; int main() { A<int> a1; //顯示模板實參的隱式實例化 a1.print(); A<char*> a2; //使用特化的類模板 A2.print(); }
程序輸出結果如下:
A'num:6
A' special definition
2.模板偏特化
2.1概述
模板偏特化(template partitial specialization)是模板特化的一種特殊情況,指指定模板參數而非全部模板參數,或者模板參數的一部分而非全部特性,也稱為模板部分特化。與模板偏特化相對的是模板全特化,指對所有的模板參數進行特化。模板全特化與模板偏特化共同組成模板特化。
模板偏特化主要分為兩種,一種是指對部分模板參數進行全特化,另一種是對模板參數特性進行特化,包括將模板參數特化為指針、引用或是另外一個模板類。
2.2函數模板偏特化
假如我們有一個compare函數模板,在比較數值類型時沒有問題,如果傳入的數值的地址,我們需要兩個數值的大寫,而非比較傳入的地址大小。此時我們需要對compare函數模板進行偏特化。考察如下代碼:
#include <vector> #include <iostream> using namespace std; //函數模板 template<typename T, class N> void compare(T num1, N num2) { cout << "standard function template" << endl; if(num1>num2) cout << "num1:" << num1 << " > num2:" << num2 <<endl; else cout << "num1:" << num1 << " <= num2:" << num2 << endl; } //對部分模板參數進行特化 template<class N> void compare(int num1, N num2) { cout<< "partitial specialization" <<endl; if (num1>num2) cout << "num1:" << num1 << " > num2:" << num2 << endl; else cout << "num1:" << num1 << " <= num2:" << num2 << endl; } //將模板參數特化為指針 template<typename T, class N> void compare(T* num1, N* num2) { cout << "new partitial specialization" << endl; if (*num1>*num2) cout << "num1:" << *num1 << " > num2:" << *num2 << endl; else cout << "num1:" << *num1 << " <= num2:" << *num2 << endl; } //將模板參數特化為另一個模板類 template<typename T, class N> void compare(std::vector<T>& vecLeft, std::vector<T>& vecRight) { cout << "to vector partitial specialization" << endl; if (vecLeft.size()>vecRight.size()) cout << "vecLeft.size()" << vecLeft.size() << " > vecRight.size():" << vecRight.size() << endl; else cout << "vecLeft.size()" << vecLeft.size() << " <= vecRight.size():" << vecRight.size() << endl; } int main() { compare<int,int>(30,31);//調用非特化版本compare<int,int>(int num1, int num2) compare(30,'1'); //調用偏特化版本compare<char>(int num1, char num2) int a = 30; char c = '1'; compare(&a,&c); //調用偏特化版本compare<int,char>(int* num1, char* num2) vector<int> vecLeft{0}; vector<int> vecRight{1,2,3}; compare<int,int>(vecLeft,vecRight); //調用偏特化版本compare<int,char>(int* num1, char* num2) }
程序輸出結果如下:
standard function template
num1:30 <= num2:31
partitial specialization
num1:30 <= num2:1
new partitial specialization
num1:30 <= num2:1
to vector partitial specialization
vecLeft.size()1 <= vecRight.size():3
2.3類模板偏特化
類模板的偏特化與函數模板的偏特化類似。考察如下代碼:
#include <vector> #include <iostream> using namespace std; //類模板 template<typename T, class N> class TestClass { public: static bool comp(T num1, N num2) { cout <<"standard class template"<< endl; return (num1<num2) ? true : false; } }; //對部分模板參數進行特化 template<class N> class TestClass<int, N> { public: static bool comp(int num1, N num2) { cout << "partitial specialization" << endl; return (num1<num2) ? true : false; } }; //將模板參數特化為指針 template<typename T, class N> class TestClass<T*, N*> { public: static bool comp(T* num1, N* num2) { cout << "new partitial specialization" << endl; return (*num1<*num2) ? true : false; } }; //將模板參數特化為另一個模板類 template<typename T, class N> class TestClass<vector<T>,vector<N>> { public: static bool comp(const vector<T>& vecLeft, const vector<N>& vecRight) { cout << "to vector partitial specialization" << endl; return (vecLeft.size()<vecRight.size()) ? true : false; } }; int main() { //調用非特化版本 cout << TestClass<char, char>::comp('0', '1') << endl; //調用部分模板參數特化版本 cout << TestClass<int,char>::comp(30, '1') << endl; //調用模板參數特化為指針版本 int a = 30; char c = '1'; cout << TestClass<int*, char*>::comp(&a, &c) << endl; //調用模板參數特化為另一個模板類版本 vector<int> vecLeft{0}; vector<int> vecRight{1,2,3}; cout << TestClass<vector<int>, vector<int>>::comp(vecLeft,vecRight) << endl; }
程序輸出結果:
standard class template
1
partitial specialization
1
new partitial specialization
1
to vector partitial specialization
1
3.模板類調用優先級
對主版本模板類、全特化類、偏特化類的調用優先級從高到低進行排序是:全特化類>偏特化類>主版本模板類。這樣的優先級順序對性能也是最好的。
但是模板特化并不只是為了性能優化,更多是為了讓模板函數能夠正常工作,最典型的例子就是STL中的iterator_traits。algorithm中大多數算法通過iterator對象來處理數據,但是同時允許以指針代替iterator對象,這是為了支持C-Style Array。如果直接操作iterator,那么為了支持指針類型,每個算法函數都需要進行重載,因為指針沒有::value_type類型。為了解決這個問題,STL使用了iterator_traits對iterator特性進行封裝,并為指針類型做了偏特化處理,算法通過它來操作iterator,不需要知道實際操作的是iterator對象還是指針。
template<typename IteratorClass> class iterator_traits
...
template<typename ValueType> class iterator_traits<ValueType*>
...
template<typename ValueType> class iterator_traits<ValueType const*>
...
后面兩是針對指針類型的偏特化,也是偏特化的一種常見形式。
以上就是深入分析C++模板特化與偏特化的詳細內容,更多關于C++模板特化與偏特化的資料請關注億速云其它相關文章!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。