## [$]一.实例化
### 1.隐式实例化
模板被使用时,进行的模板的实例化。
对于类模板,若成员函数不使用,则不会进行实例化。
+ **发生时机** 模板被使用时。
+ **缺点** 相同的模板实例可能出现在多个对象文件中,造成了一定的额外开销。
#### 例1
```c++
template <typename T>
T add(const T &t1,const T &t2)
{
return t1+t2;
}
```
调用:
```c++
f(200,700);//隐式实例化
f<int>(300,600);//隐式实例化:尽管指定了模板实参,但模板仍在被使用时才进行实例化。
```
### [11+]2.显式实例化
1. 声明显式实例化:告诉编译器在其他地方有显式实例化的定义。
+ 必须出现在使用之前,防止使用时的初始化。
```c++
extern template class Array<int>;//类模板显式声明
extern template int add(const int &,const int &);//函数模板显式声明
```
2. 定义显式实例化:只能定义一次,此时编译器会为该模板生成代码。
+ 当显式实例化类模板时,会实例化所有的成员函数。
```c++
template class Array<int>;//类模板显式定义
template int add(const int &,const int &);//函数模板显式定义
```
## [$]二.模板特例化
### 1.基本概念
1. **概念** 模板特例化是函数模板、类模板、成员模板的 **重定义** ,其中指定了部分或全部模板参数。
2. 模板特例化版本必须出现在原模板的声明之后。
3. 模板特例化的本质是实例化一个模板,而非重载它。
4. 当编译器匹配到特例化的版本时,编译器会直接使用特例化的版本,而不是重新实例化原来的模板。
### 2.函数模板特例化
当我们特例化一个函数模板时,必须为原模板中的每个模板参数都提供模板实参。且提供的模板实参必须与模板匹配。
#### 例2
下面是一个函数的多个定义,以支持字符串、字符数组的比较。
```c++
//通用模板
template <typename T>
int compare(const T &t1, const T &t2)
{
cout << "调用第一个版本" << endl;
if (t1 > t2)
return 1;
if (t1 == t2)
return 0;
if (t1 < t2)
return -1;
return 0;
}
//这是重载,不是特例化,用于字符数组的传入
template <unsigned N1, unsigned N2>
int compare(const char (&p1)[N1], const char (&p2)[N2])
{
cout << "调用第二个版本" << endl;
return strcmp(p1, p2);
}
//特例化的模板,T=const char *,用于字符指针的传入
template <>
int compare(const char *const &p1, const char *const &p2)
{
cout << "调用第三个版本" << endl;
return strcmp(p1, p2);
}
```
调用:
```c++
const char *p1 = "apple";
const char *p2 = "zoo";
cout << compare(10, 9) << endl;
cout << compare("apple", "zoo") << endl;
cout << compare(p1, p2) << endl;
```
>[test]
>调用第一个版本
>1
>调用第二个版本
>-1
>调用第三个版本
>-1
### 3.类模板特例化
+ 与函数模板不同,类模板的特例化不必为所有模板参数提供实参。
+ 一个类模板的部分特例化本身是一个模板,使用它时还须提供其余的模板实参。
```c++
//模板
template <typename T>
class A {
//code
};
//特例化
class A<char *> {
//code
};
//部分特例化
template <typename T>
class A<T&> {
//code
};
```
### 4.特例化成员
+ 与函数模板类似,需要提供全部模板实参。
```c++
template <typename T>
class Array {
private:
static int size;
//其他数据成员...
public:
void output()
{
//code
}
//其他函数...
};
//特例化成员函数
template <>
Array<int>::output()
{
//code
}
//特例化静态数据成员
template <>
Array<int>::size = 20;
```
- 阅读说明
- 1.1 概述
- C++基础
- 1.2 变量与常量
- 1.2.1 变量
- 1.2.2 字面值常量
- 字符型常量
- 数值型常量
- 1.2.3 cv限定符
- 1.3 作用域
- 1.3.1 标识符
- 1.3.2 *命名空间
- 1.3.3 作用域
- 1.3.4 可见性
- 1.4 数据类型
- 1.4.1 概述
- 1.4.2 处理类型
- 类型别名
- * auto说明符
- * decltype说明符
- 1.4.3 数组
- 1.4.4 指针
- 1.4.5 引用
- 1.5 表达式
- 1.5.1 概述
- 1.5.2 值的类别
- 1.5.3 *初始化
- 1.5.4 运算符
- 算术运算符
- 逻辑和关系运算符
- 赋值运算符
- 递增递减运算符
- 成员访问运算符
- 位运算符
- 其他运算符
- 1.5.5 *常量表达式
- 1.5.6 类型转换
- 第2章 面向过程编程
- 2.1 流程语句
- 2.1.1 条件语句
- 2.1.2 循环语句
- 2.1.3 跳转语句
- 2.1.4 *异常处理
- 2.2 函数
- 2.2.1 概述
- 2.2.2 函数参数
- 2.2.3 内置函数
- 2.2.4 函数重载
- 2.2.5 * 匿名函数
- 2.3 存储和生命期
- 2.3.1 生命周期与存储区域
- 2.3.2 动态内存
- 2.4 *预处理命令
- 第3章 面向对象编程
- 3.1 概述
- 3.2 类和对象
- 3.3 成员
- 3.3.1 访问限制
- 3.3.2 常成员
- 3.3.3 静态成员
- 3.3.4 成员指针
- 3.3.5 this指针
- 3.4 特殊的成员函数
- 3.4.1 概述
- 3.4.2 构造函数
- 3.4.3 析构函数
- 3.4.4 拷贝语义
- 3.4.5 * 移动语义
- 3.5 友元
- 3.6 运算符重载与类型转换
- 3.6.1 概述
- 3.6.2 重载方法
- 3.6.3 类型转换
- 3.7 继承与多态性
- 3.7.1 概述
- 3.7.2 派生类
- 3.7.3 子类型
- 3.7.4 虚基类
- 3.7.5 虚函数
- 3.7.6 抽象类
- 3.8 模板与泛型
- 3.8.1 概述
- 3.8.2 模板类型
- 3.8.3 *模板参数
- 3.8.4 *模板编译
- 3.8.5 *模板推断
- 3.8.6 *实例化与特例化
- 第4章 C++标准库
- 4.1 概述
- 4.2 输入输出流
- 4.2.1 概述
- 4.2.2 *流的状态
- 4.2.3 *常用流
- 4.2.4 *格式化I/O
- 4.2.5 *低级I/O
- 4.2.6 *随机访问
- 4.3 *C输入输出
- 4.3.1 *字符输入输出
- 4.3.2 *格式化输入输出
- 4.4 * 容器
- 4.4.1 * 概述
- 4.4.2 * 基本操作
- 4.4.3 * 顺序容器
- 4.4.4 * 迭代器
- 4.4.5 * 容器适配器
- 4.5 * 泛型算法
- 4.6 * 内存管理
- 4.6.1 * 自动指针
- 4.7 * 其他设施