模板特化对函数和函数都可以使用。它的作用是以某一模板函数或某个模板类为例,大部分情况下需要写的函数或内容是一致的,但是有些特别情况,所以我们需要单独拎出来。
template<class T, size_t N> //N:非类型模板参数
class StaticArray
{
public:
size_t arraysize()
{
return N;
}
private:
T _array[N]; //利用非类型模板参数指定静态数组的大小
};
int main()
{
StaticArray<int, 10> a1; //定义一个大小为10的静态数组
cout << a1.arraysize() << endl; //10
return 0;
}
注意:
模板用在函数上使得多种类型的参数都能用同一种方式处理,但是存在某一些参数情况下需要用不同的处理方式,所以需要模板特化。
如下代码,普通数值类型能比较,但是字符串类型就比较不了,所以我们需要模板特化。
template<class T>
bool IsEqual(T x, T y)
{
return x == y;
}
- 首先必须要有一个基础的函数模板。
- 关键字template<> 关键字template空的尖括号<>。
- 函数名后跟一对尖括号,尖括号中指定需要特化的类型。
- 函数形参表必须要和模板函数的基础参数类型完全相同,否则不同的编译器可能会报一些奇怪的错误。
处理string类型的比较,需要按字典序比较,所以特化出能比较string类型的模板特化函数,函数特化代码如下:
//基础的函数模板
template<class T>
bool IsEqual(T x, T y)
{
return x == y;
}
//对于char*类型的特化
template<>
bool IsEqual<char*>(char* x, char* y)
// 不写也可以
{
return strcmp(x, y) == 0;
}
类模板特化分全特化和偏特化(半特化)。区别是全部特化和部分特化。
template<class T1, class T2>
class Dragon
{
public:
//构造函数
Stu()
{
cout << "Stu" << endl;
}
private:
T1 _D1;
T2 _D2;
};
如果想对T1、T2是double和int时做特殊处理,则可写如下代码:
//对于T1是double,T2是int时进行特化
template<>
class Stu<double, int>
{
public:
//构造函数
Stu()
{
cout << "Stu" << endl;
}
private:
double _D1;
int _D2;
};
Stu<int, double> s1; // 调用特化
Stu<int, int> s2; // 调用普通
- 要先写普通类模板。
- 写类前先加:template<>。
- 类名后跟一对尖括号,尖括号中指定需要特化的类型。
template<class T2>
class Dragon<double, T2>
{
public:
//构造函数
Stu()
{
cout << "Stu" << endl;
}
private:
double _D1;
T2 _D2;
};
- template 偏特化类之前,先声明哪个参数不特化
- 类定义的<>中在适当位置加入类型
//两个参数偏特化为指针类型
template<class T1, class T2>
class Stu<T1*, T2*>
{
public:
//构造函数
Stu()
{
cout << "Stu" << endl;
}
private:
T1 _D1;
T2 _D2;
};
//两个参数偏特化为引用类型
template<class T1, class T2>
class Stu<T1&, T2&>
{
public:
//构造函数
Dragon()
{
cout << "Stu" << endl;
}
private:
T1 _D1;
T2 _D2;
};
T1、T2同时为指针类型或为引用类型时,会分别调用两个特化类模板。
Stu<int, int> s1; // T1 T2
Stu<int*, int*> s2; // T1* T2*
Stu<int&, int&> s3; // T1& T2&
这里理解为,如果我们要特化关于指针或引用类型时,特化方式和普通默认类型稍有不一样,需要template
class Stu
因为上面三个被干成了两部分,没有连接起来。
模板分离编译失败的原因:
在函数模板定义的地方(Add.cpp)没有进行实例化,而在需要实例化函数的地方(main.cpp)没有模板函数的定义,无法进行实例化。
所以:为什么在链接阶段错误?
答:在链接时候main中调用的两个Add实际上没有被真正定义,main发现Add没有定义是因为cpp中的实现了的函数模板没有生成对应函数,因为没有做实例化,因为函数模板不知道T实例化为什么类型。
优点:灵活、复用简单,STL的重要工具。
缺点:代码膨胀、编译时间过长、报错信息难看、不容易定位。
下列的模板声明中,其中几个是正确的( )
1)template
2)template<T1,T2>
3)template<class T1,T2>
4)template<class T1,class T2>
5)template<typename T1,T2>
6)template<typename T1,typename T2>
7)template<class T1,typename T2>
8)<typename T1,class T2>
9)template<typeaname T1, typename T2, size_t N>
10)template<typeaname T, size_t N=100, class _A=alloc<T>>
11)template<size_t N>
9、11中size_t N是非类型形参,9和11都是模板声明,关键点是跟在class和typename中即可。
共有:4\6\7\8\10\11共6个。
非模板的函数的调用优先级更高。
模板的编译:
模板不支持分离编译,分离后的模板实现需要自己写实例化,很麻烦。