C++ 模板进阶
温馨提示:这篇文章已超过406天没有更新,请注意相关的内容是否还可用!
C++ 模板进阶
- 一.非类型模板参数
- 1.概念
- 2.实例
- 3.注意事项
- 二.模板的特化
- 1.引出
- 2.函数模板的特化
- 1.语法和使用
- 2.建议
- 3.类模板的特化
- 1.全特化
- 2.偏特化
- 1.部分特化
- 2.对参数进行进一步的限制
- 4.匹配顺序
- 三.模板的分离编译
- 1.什么是分离编译
- 2.模板的分离编译
- 3.解决方法
- 1.显式实例化(不推荐)
- 2.分离编译放在头文件当中
- 四.模板的总结
一.非类型模板参数
1.概念
模板参数分为: 类型形参与非类型形参
类型形参即:出现在模板参数列表中,跟在class或者typename之类的参数类型名称后面
非类型形参,就是用一个常量作为类(函数)模板的一个参数,在类(函数)模板中可将该参数当成常量来使用
2.实例
比方说我想实现一个静态的栈,栈的大小是10
#define N 10 template class Stack { private: T _arr[N]; }; int main() { Stack st1; Stack st2; return 0; }可是我需求变了,st1我想要10个大小,st2我想要200个大小,st3我想要1000个大小,st4我想要2个大小…
怎么办?
此时就需要用到非类型模板参数了
template class Stack { private: T _arr[N]; }; int main() { Stack st1; Stack st2; Stack st3; Stack st4; return 0; }此时你st1想要10个大小,st2想要100个大小,st3想要1000个…
都可以,完美的解决了这个问题
3.注意事项
- 浮点数、类对象以及字符串是不允许作为非类型模板参数的
- 非类型的模板参数必须在编译期就能确认结果
(因为模板是在编译阶段就要实例化的,而模板必须要知道实例化成的具体类型之后才能实例化,
因此非类型模板参数和类型模板参数一样,必须在编译阶段就能够确认实例化成的具体类型才可以,
否则编译阶段无法完成实例化,链接阶段就找不到实例化出的具体的类,进而发生链接错误)
二.模板的特化
1.引出
通常情况下,使用模板可以实现一些与类型无关的代码,但对于一些特殊类型的可能会得到一些错误的结果,需要特殊处理,比如:实现了一个专门用来进行小于比较的函数模板
我们写一个非常简易的日期类,用这个日期类开始下面的介绍
这里给出了头文件,至于源文件就不给大家了,毕竟我们这篇博客的目的也不是实现日期类
关于日期类的完善大家可以看我的这篇博客:
C++类和对象中:运算符重载+const成员函数+日期类的完善
对于第三个比较,我们想要比较的其实是p1和p2,可是实际比较的是p1和p2这两个指针
不符合我们的期望,怎么办呢?
2.函数模板的特化
1.语法和使用
因此我们就可以这样特化
// 函数模板 -- 参数匹配 //基础的函数模板 template bool Less(T left, T right) { return left特化之后,如果函数模板的参数跟特化的类型是匹配的,那么就会走特化,并不会走函数的基础模板
跟我们之前学的函数模板推演实例化时如果有更匹配的会优先去匹配那个更匹配的,这个原则是一样的
2.建议
不建议大家使用函数模板的特化,而建议大家直接写一个同名的非函数模板即可,
因为:
1.函数模板的特化和直接写一个同名的非模板函数的工作量是一样的
2.函数模板的特化的要求更多
比如:必须要有一个基础的函数模板
而且函数形参表: 必须要和模板函数的基础参数类型完全相同
3.而且因为const,引用和指针的关系,导致函数模板的特化变得更加复杂
4.直接写一个同名的非函数模板:简单明了,代码的可读性高,容易书写
3.类模板的特化
1.全特化
全特化: 将模板参数列表中所有的参数都确定化
语法跟函数模板的特化非常相似
都是需要一个基础模板等等…
template class C { public: C() { cout public: C() { cout public: C() { cout public: C() { cout public: C() { cout C public: bool less(const T& a, const T& b) { return a







