概念 函数模版与类模版 C++中模板分为函数模板和类模板
所谓特化,就是将泛型搞得具体化一些,就是为已有的模板参数进行一些使其特殊化的指定,使得以前不受任何约束的模板参数,或受到特定的修饰或完全被指定了下来。
分类 针对特化的对象不同,分为
函数模板的特化 – 当函数模板需要对某些类型进行特化处理,称为函数模板的特化。
类模板的特化 – 当类模板内需要对某些类型进行特别处理时,使用类模板的特化。
特化整体上分为全特化 和偏特化
我们只能偏特化类模板,而不能偏特化函数模板,因为函数偏特化的功能可以通过函数的重载完成。
函数模板的特化 编写单一模板,使之对任何可能的模板实参都是最适合的,都能实例化。但是在某些情况下,通用模板的定义对特定类型是不适合的。即使用模板时会遇到一些特殊的类型需要特殊处理,不能直接使用当前的模板函数,所以此时我们就需要对该类型特化出一个模板函数(就是写出一个模板函数专门给该类型使用)。
例1
当使用一个比较大小的模板函数时
1 2 3 4 5 template <typename T> T compare (T &t1, T &t2) { cout <<"in template<typename T> ..." <<endl; return (t1 > t2) ? t1 : t2; }
但是该模板函数在对于字符串进行比较时就不能使用了,对于字符串我们不能直接比较,因此直接特化出一个专门供字符串使用的模板参数。
1 2 3 4 5 template <> const char * compare <const char *>(const char * &s1, const char * &s2) { cout <<"in special template< >..." <<endl; return (strcmp (s1,s2) > 0 ) ? s1:s2; }
或者
1 2 3 4 5 template <> const char * compare (const char * &s1, const char * &s2) { cout <<"in special template< >..." <<endl; return (strcmp (s1,s2) > 0 ) ? s1:s2; }
函数模版的特化,当函数调用发现有特化后的匹配函数时,会优先调用特化的函数,而不再通过函数模版来进行实例化。
注意:
特例化一个函数模板时,必须为原模板中的每个模板参数类型都提供实参。使用关键字template
后跟一个空尖括号对<>
,其指出我们将为原模板的所有模板参数提供实参;
函数名<特化类型>(特化类型 参数1, 特化类型 参数2 , …) 在函数名后跟<>其中写要特化的类型;
当我们定义一个特例化版本时,函数参数类型必须与一个先前声明的模板中对应的类型匹配,即特化的函数的函数名,参数列表要和原基础的模板函数想相同。
在实际使用中,为了实现简单,对于一些模板函数处理有问题的特殊类型,我们将其直接写出
1 2 3 4 5 6 int compare (const char * &t1, const char * &t2) { cout <<"in overload function..." <<endl; return strcmp (t1, t2); }
当有可以直接匹配的函数时,即使有特化出的函数,都优先使用直接匹配的函数
例2
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 #include <iostream> #include <cstring> using namespace std;template <typename T> T compare (T &t1, T &t2) { cout <<"in template<typename T> ..." <<endl; return (t1 > t2) ? t1 : t2; } template <> const char * compare <const char *>(const char * &s1, const char * &s2) { cout <<"in special template< >..." <<endl; return (strcmp (s1,s2) > 0 ) ? s1:s2; } int compare (const char * &left, const char * &right) { cout <<"in overload function..." <<endl; return strcmp (left, right); } int main ( ) { int a = 1 , b = 2 ; compare (a, b); const char *left = "gatieme" ; const char *right = "jeancheng" ; compare (left, right); return 0 ; }
面试题 写一个模板特化函数printType,当T是int输出”I am int”,其他则输出”I am other”。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 #include <iostream> using namespace std;template <typename T>void printType (const T &a) { cout<<"I am other" <<endl; } template <>void printType (const int &a) { cout<<"I am int" <<endl; } int main () { int a = 1 ; string b = "hello" ; printType (a); printType (b); return 0 ; }
类模板特化 类模板支持全特例化和偏特化,区别在于模板参数是否全部显示指定,或者全部参数性质指定。
类模板全特化 类模板特化类似于函数模板的特化,即类模板参数在某种特定类型下的具体实现。考察如下代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 #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 <const char *> { const char * str; public : A () { str = "A special definition" ; } void print () { cout<<str<<endl; } }; int main () { A<int > a1; a1.print (); A<const char *> a2; a2.print (); }
类模板偏特化 模板偏特化(Template Partitial Specialization)是模板特化的一种特殊情况,指显示指定部分模板参数而非全部模板参数,或者指定模板参数的部分特性分而非全部特性,也称为模板部分特化。与模板偏特化相对的是模板全特化,指对所有模板参数进行特化。模板全特化与模板偏特化共同组成模板特化。
模板偏特化主要分为两种,一种是指对部分模板参数进行全特化,另一种是对模板参数特性进行特化,包括将模板参数特化为指针、引用或是另外一个模板类。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 #include <vector> #include <iostream> using namespace std;template <typename T, class N > class TestClass {public : static bool compare (T num1, N num2) { cout <<"standard class template" << endl; return (num1 < num2) ? true : false ; } }; template <class N > class TestClass <int , N> {public : static bool compare (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 compare (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 compare (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 >::compare ('0' , '1' ) << endl; cout << TestClass<int , char >::compare (30 , '1' ) << endl; int a = 30 ; char c = '1' ; cout << TestClass<int *, char *>::compare (&a, &c) << endl; vector<int > vecLeft{0 }; vector<int > vecRight{1 ,2 ,3 }; cout << TestClass<vector<int >, vector<int >>::compare (vecLeft,vecRight) << endl; }
模板类调用优先级 对主版本模板类、全特化类、偏特化类的调用优先级从高到低进行排序是:
全特化类 > 偏特化类 > 主版本模板类
这样的优先级顺序对性能也是最好的。