为了实现与数据类型无关的编程,模板应运而生:
1 #include<iostream>
2 #include<string.h>
3 using namespace std;
4
5 template <typename T>
6 void compare(T *obj1, int size)
7 {
8 int i, j;
9 T temp;
10 for(i=0;i<size;i++)
11 for (j = i + 1; j < size; j++)
12 {
13 if (obj1[i] < obj1[j])
14 {
15 temp = obj1[i];
16 obj1[i] = obj1[j];
17 obj1[j] = temp;
18 }
19 }
20
21 }
22
23
24 int main()
25 {
26 int a[] = { 1,5,2,7,4,9 };
27 int size = sizeof(a) / sizeof(*a);
28 compare<int>(a, size);
29 for (int i = 0; i < size; i++)
30 {
31 printf("%d ", a[i]);
32 }
33
34 char ca[] = "abcdefg";
35 int csize = strlen(ca);
36 compare<char>(ca, csize);
37 printf("%s", ca);
38 cout << "hello...\n";
39 return 0;
40 }
模板定义以关键字template开始,后跟模板参数列表,这是一个逗号分隔的一个或多个模板参数的列表,用小于号(<)和大于号(>)包围起来。当使用模板时,我们隐式或者显式地指定模板实参,将其绑定到模板参数上。(建议都显式指定)。
类型参数前必须使用class或者typename,在模板参数列表中这两个关键字含义相同,可以互换。typename更为直观,但是,typename是在模板已经广泛使用后才引入c++语言的,某些以前的程序,使用class,我们也得知道是什么意思。
模板与非模板代码不同,函数模板和类模板成员函数的定义通常放在头文件中。
当编译器遇到一个模板的定义时,并不生成代码。只有我们实例化出模板的一个特定版本时,编译器才会生成代码。当我使用(而不是定义)模板时,编译器才生成代码这一特性影响了我们如何组织代码以及错误何时被检测到。通常,编译器会在三个阶段报告错误:
1.编译模板本身时,这个阶段编译器通常不会发现很多错误。编译器可以检查语法错误,例如忘记分号或者变量名拼错等,但也就这么多了。
2.编译器遇到模板使用时,在此阶段,编译器任然没有很多可检查的。对于函数模板调用,编译器通常会检查实参数目是否正确,它还能检查参数类型是否匹配。对于类模板,编译器可以检查用户是否提供了正确数目的模板实参,但也仅限于此了。
3.模板实例化时,只有这个阶段才能发现类型相关的错误。依赖于编译器如何管理实例化,这类错误可能在链接时才报告。
保证传递给模板的实参支持模板所要求的的操作,以及这些操作再模板中能正确工作,是调用者的责任。