在前面我们学习了模板的基础用法【c++】 模板初阶-CSDN博客初步认识了函数模板和类模板,接下来让我们看看模板还有哪些进阶的应用。
非类型模板参数
之前我们用到的模板全都使用了类型参数
类型参数:表示某种数据类型(如 int
、double
、自定义类等)。
非类型参数:表示常量值(如整数、指针、引用等)。
这样模板的每一个类型参数都要由我们传入的数据类型在实例化的时候由编译器确定。在一些特定的情况,会用到常量;如我们需要一个定长的数组时。控制数组长度的类型时确定的(如size_t),这样我们只设置一个类型参数就可以了。
namespace xian
{//定义一个模板类型的定长数组template<typename T,size_t N>class array{public:T& operator[](size_t n){return _array[n];}const T& operator[](size_t n) const{return _array[n];}size_t size(){return _size;}bool empty(){return 0 == _size;}private:T _array[N];size_t _size;};}
注意:非类型模板参数只能用于整型;不支持浮点数,类对象和字符串。c++20之后可以支持double作非类型模板参数。
非类型模板参数支持缺省值:
template<size_t N = 10>class Stack{private:int a[N];int _top;};int main(){//Stack s0; 这种写法要c++20以后才支持Stack<> s1; //我们还是用这种写法的好}
模板的特化
函数模板的特化
// 函数模板 -- 参数匹配
template<class T>
bool Less(T left, T right)
{return left < right;
}int main()
{cout << Less(1, 2) << endl;Date d2(2022, 7, 8);Date d1(2022, 7, 7);cout << Less(d1, d2) << endl;//可以正常判断Date* p2 = &d2;Date* p1 = &d1;cout << Less(p1, p2) << endl; //会直接比较指针return 0;
}
根据地址比较大小,而地址的申请时随机的,这样结果是不能确定的。对于这种有特殊情况的可以使用模板的特化,把特殊情况单独拿出来处理。
// 函数模板 -- 参数匹配
template<class T>
bool Less(T left, T right)
{return left < right;
}// 对Less函数模板进行特化
template<>
bool Less<Date*>(Date* left, Date* right)
{return *left < *right;
}
int main()
{cout << Less(1, 2) << endl;Date d2(2022, 7, 8);Date d1(2022, 7, 7);cout << Less(d1, d2) << endl;//可以正常判断Date* p2 = &d2;Date* p1 = &d1;cout << Less(p1, p2) << endl; //会直接比较指针return 0;
}
有特化后的类之后,会直接使用特化后的类。
总结:
-
主模板:定义通用的函数模板。
-
特化版本:为特定类型提供定制化实现。
-
调用:编译器根据参数类型自动选择主模板或特化版本。
-
注意事项:特化版本的函数签名必须与主模板一致,且不支持偏特化。
大多数时候,我们都选择简单的方法直接把特殊的情况函数直接给出而不是使用特化。使用特化容易出错,一般不要使用函数模板特化
类模板的特化
全特化
全特化就是将模板参数全部特化
//全特化
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 TestVector()
{Data<int, int> d1;Data<int, char> d2;
}
偏特化
偏特化是对模板参数部分特化,不仅仅是列出部分模板参数的具体类型,也可能是对原始模板作一些限制。
偏特化一共有两种表现方式:
部分特化
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, char>
{
public:Data() { cout << "Data<int, char>" << endl; }
private:T1 _d1;char _d2;
};
void TestVector()
{Data<int, int> d1;Data<int, char> d2;
}template <class T1>
class Data<T1, int>
{
public:Data() { cout << "Data<T1, int>" << endl; }
private:T1 _d1;int _d2;
};
限制参数
template<class T1, class T2>
class Data
{
public:Data() { cout << "Data<T1, T2>" << endl; }
private:T1 _d1;T2 _d2;
};//限制传入的数据类型为指针template<class T1, class 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() { cout << "Data<T1, T2>" << endl; }
private:T1 _d1;T2 _d2;
};