模板
模板参数分类类型形参与非类型形参。
类型形参即:出现在模板参数列表中,跟在class或者typename之类的参数类型名称。
非类型形参
非类型形参,就是用一个常量作为类**(函数)模板的一个参数,在类(函数)**模板中可将该参数当成常
量来使用。
cpp
//非类型模板参数
//宏定义也可以完成,但宏定义没有该操作自由,可以多个不一样的N
// 注意只能是常量变量,字符 布尔值 可以 但浮点数 字符串不行
template<class T, size_t N = 10>//设立缺省值
class Array {
public:
size_t size()const {
return _size;
}
T& operator[](size_t n)
{
return _data[n];
}
T& operator[](size_t n) const
{
return _data[n];
}
bool empty()
{
return _size == 0;
}
private:
T _data[N];
size_t _size = N;
};
模板特化
通常情况下,使用模板可以实现一些与类型无关的代码,但对于一些特殊类型的可能会得到一些****错误的结果,需要特殊处理,比如:实现了一个专门用来进行小于比较的函数模板
函数模板特化
函数模板的特化步骤:
- 必须要先有一个基础的函数模板
- 关键字template后面接一对空的尖括号<>
- 函数名后跟一对尖括号,尖括号中指定需要特化的类型
- 函数形参表: 必须要和模板函数的基础参数类型完全相同,如果不同编译器可能会报一些奇 怪的错误。
通用模板及通用模板特化
模板特化分为全特化和偏特化
全特化:全特化即是将模板参数列表中所有的参数都确定化。
偏特化:任何针对模版参数进一步进行条件限制设计的特化版本
cpp
//通用形式
template<class T1,class T2>
class func {
public:
func(const T1& m, const T2& n)
:_begin(m)
, _end(n)
{
cout << "T1" << " " << "T2" << endl;
cout << _begin << " " << _end<<endl;
}
private:
T1 _begin;
T2 _end;
};
//全特化 设两个参数为double
template<>
class func<double,double> {
public:
func(double m,double n)
:_begin(m)
, _end(n)
{
cout << "double" << " " << "double" << endl;
cout << _begin << " " << _end<<endl;
}
private:
double _begin;
double _end;
};
//偏特化 半特化
template<class T>
class func<T, double> {
public:
func(const& m, double n)
:_begin(m)
, _end(n)
{
cout << "T" << " " << "double" << endl;
cout << _begin << " " << _end << endl;
}
private:
T _begin;
double _end;
};
指针模板特化
cpp
//指针的特化
template<class T1,class T2>
class func<T1*,T2*> {
public:
func(const T1& m, const T2& n)
:_begin(m)
, _end(n)
{
cout << "T1*" << " " << "T2*" << endl;
cout << _begin << " " << _end << endl;
}
private:
T1 _begin;
T2 _end;
};
引用模板特化
cpp
//引用
template<class T1, class T2>
class func<T1&, T2&> {
public:
func(const T1& m, const T2& n)
:_begin(m)
, _end(n)
{
cout << "T1&" << " " << "T2&" << endl;
cout << _begin << " " << _end << endl;
}
private:
T1 _begin;
T2 _end;
};
模板分离编译
什么是模板分离链接
一个程序(项目)由若干个源文件共同实现,而每个源文件单独编译生成目标文件,最后将所有目标文件链接起来形成单一的可执行文件的过程称为分离编译模式。
模板的分离编译示例
假如有以下场景,模板的声明与定义分离开,在头文件中进行声明,源文件中完成定义
cpp
// a.h
template<class T>
T Add(const T& left, const T& right);
// a.cpp
template<class T>
T Add(const T& left, const T& right)
{
return left + right;
}
// main.cpp
#include"a.h"
int main()
{
Add(1, 2);
Add(1.0, 2.0);
return 0;
}
会显示链接错误,原因就是模板的定义与声明分开在不同文件使用了
在main.cpp中,运行到.Add,因为包含的a.h中有Add的声明,所以不会报错,但调用Add的函数时,却错误,我们不是在a.cpp进行了Add的定义吗?
但事实上是main.cpp在调用Add的函数时,找不到地址
解决方法
- 定义与声明放到同一个文件上
- 显示实例化(不推荐)
总结:
- 非类型形参可以让我们在传参时更加灵活
- 模板特化可以为特定类型提供特定方式,有全特化和偏特化
- 要正确理解模板分离编译的问题所在