1. 编写类型无关的代码
泛型代码的两个重要原则:
模板中的函数参数是const的引用。函数体中的条件判断仅使用<比较运算。
大多数类型,包括内置类型和我们已经用过的标准库类型(除unique_ ptr和I0类型之外),都是允许拷贝的。但是,不允许拷贝的类类型也是存在的。通过将参数设定为const的引用,保证了这些类型可以用我们的compare函数来处理。
1.1 同时支持<运算符和>运算符
//期望的比较操作if (v1 < v2) return -1;if (v1 > v2) return 1;return 0;
1.2 只支持< ,则是类型无关和可移植性
用less 来定义我们的函数:
//即使用于指针也正确的compare版本template <typename T> int compare (const T &vl, const T &v2)if (less<T>() (v1, v2)) return -1;if (less<T>() (v2, v1)) return 1;return 0;
2. 模板编译
为了生成一个实例化版本,编译器需要掌握函数模板或类模板成员函数的定义。因此,与非模板代码不同,模板的头文件通常既包括声明也包括定义。
模板包含两种名字:
那些不依赖于模板参数的名字
当使用模板时,所有不依赖于模板参数的名字都必须是可见的,这是由模板的提供者来保证的。而且,模板的提供者必须保证,当模板被实例化时,模板的定义,包括类模板的成员的定义,也必须是可见的。
那些依赖于模板参数的名字
用来实例化模板的所有函数、类型以及与类型关联的运算符的声明都必须是可见的,这是由模板的用户来保证的。
2.1 头文件
编写模板:必须提高头文件,包含模板定义以及在类模板或成员定义中用到的所有名字的声明。
调用模板:必须包含模板的头文件,以及用来实例化模板的任何类型的头文件。
2.2 模板代码假设
模板代码不针对特定类型,但通常对其所使用的类型有一些假设。
eg. compare模板假定实参类型定义了<运算符。
if (v1 < v2) return -1; //要求类型T的对象支持<操作.if (v2 < v1) return 1; //要求类型T的对象支持<操作用户调用时得符合假设,否则出错Sales data datal, data2;cout << compare (datal, data2) << endl; //错误: Sales_ data未定义<