humid1ch blogs

本篇文章

手机用户建议
PC模式 或 横屏
阅读


C++ 2022 年 7 月 18 日

[C++] 模板的特化相关介绍: 非类型模板参数、模板的全特化、偏特化分析、迭代器萃取分析...

之前关于模板 还有一些问题没有解决, 本篇文章就是对模板 提出问题和解决问题的
本篇文章是 C++ 模板的第二篇文章, 第一篇文章简单介绍了模板的函数模板、类模板的相关定义及调用等
然而 从初始模板到这篇文章之间, 已经介绍了C++中有关 string、vector、stack、queue、priority_queue、iterator的功能、实现等内容, 相信 对模板已经有了一定的认识
但是模板还有一些问题没有解决, 本篇文章就是对模板 提出问题和解决问题的

非类型模板参数

在一般的模板中, 无论是函数模板还是类模板, 他们的定义都是, 像这样的:
模板参数都是 虚拟的, 传参时都需要传类型, 但是 在定义模板时, 模板参数还有另一种形式
即, 不传 类型, 而是已经知道了类型 传数值, 叫做非类型模板参数, 并且 C++11 引入了一种使用非类型模板参数的容器 叫 array

什么是 非类型模板参数?

其实查看一下 array 容器的模板定义一眼就可以看出来什么是 非类型模板参数:
对, 没错, 非类型模板参数就是已经知道类型的模板参数。使用这个模板 在传参的时候, 除了传类型之外, 还要传入指定类型的数值

其实 非类型模板参数只能传入整型数值: size_t、int、char

并且, 传入的数值是一个常量, 具有常性无法修改!!

而在 array 这个容器中, size_t N 这个模板参数的作用, 是为了定义一个大小为N的数组准备的, 并且这个数组是静态的, 与C语言中原生定义的数组没有什么区别:
也就是说, 在容器 array 中, 存在的非类型模板参数是为了指定需要定义数组的大小

array 这个容器, 其实就是 C语言中的原生数组, 只不过在C++中 封装实现了

array 相比原生的数组, 具有优势的地方好像只有一个: array 实例化的对象, 边界检查相比原生指针更准确

因为 array 的边界是 assert 强制检查的

array 没有什么需要注意的地方, 一般只用于开辟大数据的静态数组
但是 由于他是在内存的栈区 开辟空间的, 而栈区又很小, 所以还是不常用, 还是 vector 用的多

模板的特化

特化的概念

C++ 模板是泛型编程的一种, 是为了一套代码 多方使用而出现的
但是 在实际的使用中总会有 特殊的类型需要特殊的处理的情况发生, 就比如这样:
greater 是一个函数模板, 是用来比较两个类型的大小的 在使用时, 对于a, b 这两个变量可以直接 返回正确的返回值, 但是 当传入的是 a, b 的指针时, 就会发生错误:
因为, greater 函数是作用是 直接对比传入类型的数据, 而 c, d 是两个指针 指针对比是对比的地址大小而不是指针指向的内容大小, 所以对于这样的情况就需要 特殊处理:
经过特化处理的类型, 再使用函数模板时, 会调用最适合的函数模板:
不会再出现, 返回值错误的情况

当然, 当前只是以 函数模板 举一个例子, 来解释一下什么特化, 真正的编程中, 一般不对函数模板特化, 因为特化需要制定 类型, 函数模板被指定类型其实跟 定义一个特定类型的函数没什么区别, 所以 一般不对函数模板特化, 重新再写一个重载函数就行了

一句话总结模板的特化就是: 在原模板的基础上, 针对指定类型所进行单独、特殊处理的实现方式 模板特化中分为 函数模板特化类模板特化
上面介绍的是函数模板特化, 其特化的条件是:
  1. 必须先有基础模板, 才能特化
  2. 关键字template后面接一对 空的尖括号<>
  3. 函数名后跟一对尖括号, 尖括号中指定需要特化的类型, 即 <指定类型>
  4. 函数形参表必须要和模板函数的基础参数类型完全相同 即, 基础参数类型有几种, 特化就要有几种
而 类模板的特化 更经常使用, 下面介绍类模板的特化

类模板的特化

类模板的特化 随便一个类模板为例:

使用此模板实例化对象时, 会打印: TT <T1, T2>, 即 调用原模版

类模板的特化有 两种形式: 全特化和偏特化
下面一一来介绍

类模板全特化

类模板全特化的意思是, 对 类模板所有的模板参数进行特化处理, 即像这样
当类模板对指定类型特化时, 使用指定的类型实例化对象就会调用 特化版的类模板:

类模板的全特化 与 函数模板的特化, 其实都不经常使用, 因为类模板的全特化也像是直接定义了一个指定类型的类而已, 类模板的特化更重要的、更常用的是, 类模板的偏特化(半特化)

类模板的偏特化

类模板偏特化的作用更像是对类模板的限制, 而不是指定类
偏特化有两种 表现形式:

1. 部分特化

看名字就可以看出来, 部分特化, 即 将类模板参数列表中的一部分参数特化
而 当对象实例化的时候, 如果第二个参数是 double, 那么就会调用 特化过的类模板进行实例化:
除了这种, 对类模板参数部分特化的偏特化之外, 还有另外一种形式

2. 参数形式限制特化

特化 并不仅仅只是将模板参数特定为某一个类型, 更可以将参数模板特化为 某种类型:
特化 更可以对特定的某种类型处理:

注意: 只有所有参数都满足特化类型时, 才会去调用特化类模板


迭代器萃取

版权声明:自由转载-非商用-非衍生-保持署名(创意共享3.0许可证)

作者: 哈米d1ch 发表日期:2022 年 7 月 18 日