我们另一篇模板初阶介绍链接:http://t.csdn.cn/Ox8Dm
目录
一、非类型模板参数
1.1 非类型模板参数概念
1.2 模板类型的静态数组
二、模板特化
2.1 函数模板特化
2.2 类模板特化
2.2.1 类模板全特化
2.2.2 类模板半特化(偏特化)
2.2.3模板特化应用场景
一、非类型模板参数
1.1 非类型模板参数概念
模板参数分为类型参数和非类型参数!
类型参数就是出现在模板参数列表中,跟在class 或者typename之类的参数类型名称。
非类型参数就是用一个常量作为类(函数)模板的一个参数,在类(函数)模板中可将该参数当成常量来使用。
1.2 模板类型的静态数组
将数组封装成类,类成员是一个数组!我们可以通过传非类型模板参数定义数组的大小!这样我们手动调控静态数组大小!
template<class T,size_t N=10>
class Array
{
public:
Array()
{
for (size_t i = 0;i <_size;i++)
{
_arr[i] = i+1;
}
}
T operator[](size_t n)
{
assert(n < _size);//只要发生越界直接报错
return _arr[n];
}
size_t size()const
{
return _size;
}
private:
T _arr[N];
size_t _size=N;
};
测试一下效果:
二、模板特化
2.1 函数模板特化
通常情况下,使用模板可以实现一些与类型无关的代码,但对于一些特殊类型的可能会得到一些错误的结果,需要特殊处理,比如:实现了一个专门用来进行小于比较的函数模板!
我们实现了一个比较模板函数,下面我们预比较不同类型的数据:
//模板函数
template<class T>
bool Less(const T& left, const T& right)
{
return left < right;
}
void Test2()
{
//整形
cout << " Less(1, 2)="<<Less(1, 2) << endl;
//日期类
Date d1(2023,1,8);
Date d2(2023,1,9);
cout << "Less(d1,d2)="<< Less(d1, d2) << endl;
//日期类,但传的是地址
Date* p1 = &d1;
Date* p2 = &d2;
cout <<"Less(p1, p2)="<< Less(p1, p2) << endl;
}
很明显我们发现同样希望比较日期类,第二个比较直接用Date类型,第三个用的是Date*,但是比较结果却相反!这与我们的期望不同!思考发现,原来第三个比较的并不是日期类,而是二者的地址,所以结果不同!这种情况下,我们理想的是比较*left与*right,但是模板函数参数限定了它的比较形式!也就是说范式的模板函数不能解决所有的比较,我们需要特例化!也就是特化函数模板!这里我们需要特化Date*比较!
函数模板的特化步骤:
1. 必须要先有一个基础的函数模板
2. 关键字template后面接一对空的尖括号<>
3. 函数名后跟一对尖括号,尖括号中指定需要特化的类型
4. 函数形参表: 必须要和模板函数的基础参数类型完全相同,如果不同编译器可能会报一些奇怪的错误。
特化Date* 代码:
template<class T>
bool Less(const T& left, const T& right)
{
return left < right;
}
template<>//这个模板列表不能省去!
bool Less<Date*>(Date* const& left, Date* const& right)
{
return *left < *right;
}
特化后比较结果:
2.2 类模板特化
2.2.1 类模板全特化
template<class T1, class T2>
class Data
{
public:
Data() { cout << "Data<T1, T2>" << endl; }
private:
T1 _d1;
T2 _d2;
};
//类模板全特化,也就是模板参数都确定化
template<>
class Data<int, char>
{
public:
Data() { cout << "Data<int, char>" << endl; }
private:
int _d1;
char _d2;
};
//全特化测试
void Test3()
{
Data<int, int> d1;
Data<int, char> d2;
}
若模板参数匹配特化的类模板参数,则优先调用特化类模板!
2.2.2 类模板半特化(偏特化)
偏特化就是部分类模板参数具体化!如果类模板所传参数满足特化模板对应位置具体化参数!则优先调用特化模板!
//一般模板函数
template<class T1, class T2>
class Data
{
public:
Data() { cout << "Data<T1, T2>" << endl; }
private:
T1 _d1;
T2 _d2;
};
//偏特化,部分位置参数确定
template <class T1>
class Data<T1, int>
{
public:
Data() { cout << "Data<T1, int>" << endl; }
private:
T1 _d1;
int _d2;
};
//指针/引用偏特化
template <typename T1, typename T2>
class Data <T1*, T2*>
{
public:
Data() { cout << "Data<T1*, T2*>" << endl; }
private:
T1 _d1;
T2 _d2;
};
template <class T1,class T2>
class Data <T1&, T2&>
{
public:
Data(const T1& d1, const T2& d2)
: _d1(d1)
, _d2(d2)
{
cout << "Data<T1&, T2&>" << endl;
}
private:
const T1& _d1;
const T2& _d2;
};
//偏特化测试
void Test4()
{
Data<double, int> d1; // 调用特化的int版本
Data<int, double> d2; // 调用基础的模板
Data<int*, int*> d3; // 调用特化的指针版本
Data<int&, int&> d4(1, 2); // 调用特化的指针版本
}
2.2.3模板特化应用场景
如果我们拿到的类型是日期类的地址,我们想要less比较的是*left和*right !但库中的一般模板参数只是比较left和right!也就是只比较地址!这样不能满足我们的需求,所以必须特化!
#include<vector>
#include<algorithm>//sort
#include <functional>//less
//模板特化应用场景
template<>
class less<Date*>
{
public:
bool operator()(Date* left,Date* right)
{
return *left > *right;
}
};
void Test5()
{
Date d1(2023, 1, 8);
Date d2(2023, 1, 9);
Date d3(2022, 12, 31);
vector<Date*> v;
v.push_back(&d1);
v.push_back(&d2);
v.push_back(&d3);
sort(v.begin(), v.end(), less<Date*>());
for (auto& e : v)
{
cout << *e;
}
}