第一章
1. 函数模板实例
根据所给定的模板参数值以及完整的函数模板声明,编译器可以自动生成一个对所需数据类型进行操作的函数,称为函数模板实例。
2. 模板参数的自动推倒
凡是可以推导出的模板参数“值”,就无需在模板实参列表中写明。
|
1
2
3
4
5
6
7
8
9
10
|
template<typename T>T const& max_element(T const *l, unsigned sz){}int main(){ int array[] = {1,2,3,4,5}; cout << max_element<int>(array, 8) << endl; cout << max_element(array, 8) << endl; //自动推导} |
利用模板参数推导需要注意以下几点:
-
编译器只根据函数调用时给出的 实参列表来推导模板参数值,与函数参数类型无关的模板参数气质无法推导
-
与函数返回值相关的模板参数其值也无法推导
-
所有可对到模板参数必须是连续位于模板参数列表尾部,中间不能有不可推导的模板参数
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
template<typename T0, typename T1, typename T2, typename T3, typename T4>T2 func(T1 v1, T3 v3, T4 v4 ){...}int main(){ ... //T0,T2不可推导 sv2 = func<double, int, int>(1,2,3); sv0 = func<double, ,int>(1,2,3); //语法错误 ...} |
3. 模板参数的默认值
在C++11标准中,允许为函数模板参数赋默认值。
|
1
2
3
4
5
6
7
8
9
|
template<typename T0 = float, typename T1, typename T2 = float, typename T3, typename T4>T2 func(T1 v1, T3 v3, T4 v4 );...//在main函数中可以以以下形式调用func(1,2,3); |
4. 模板函数的静态变量
当有多个调用使用相同的模板参数值时,编译器只为此模板参数值组生成同一函数而将不同调用都连接到同一函数上。
例如:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
template<typename T0, typename T1, typename T2, typename T3, typename T4>T2 func(T1 v1, T3 v3, T4 v4 ){ //包含一个static变量}int main(){ double a; a = func<double ,int, int>(1, 2, 3); a = func<double ,int, int>(1, 2, 3); a = func<double ,int, int>(1, 0.1, 0.1); a = func<int ,double, double>(1, 2, 3);} |
第一个和第二个编译器为其生成一个函数,而第三第四编译器为其生成不同的函数。
5. 模板函数的声明
不能将模板函数的声明和实现分别写在.h和.cpp文件当中,可以通过两种方式:
i. 使用明确生成模板实例
|
1
2
3
4
|
template<typename T>T const& func(T const &v){return v;}template int const& func(int const &v); |
ii. 对于编译器来说,模板实现也是一种声明,声明如何自动生成代码。所以模板的实现也应该放在头文件内,这样,在其他代码文件中可以直接讲模板的实现也包含进来,当 需要生成模板实例时,编译器可以根据已知模板实现当场生成,而无须依赖在别的目标文件中生成的模板实例。
6. 连接器如何识别重复模板实例
C++标准给出的解决方案是:在连接时识别及合并等价的模板实例
连接器不考虑函数的具体内容,仅仅通过函数名、模板实参列表 以及参数列表等“接口信息来判断两个函数是否等价”,可以通过使用命名空间机制来避免使用同名的函数

浙公网安备 33010602011771号