目录
函数模板:
语法:
分析:
函数调用:
怎么实现:
模板函数:
函数模板:
其实就是在函数中使用模板,我们前面的swap函数就是一个函数模板。
语法:
template <typename 类型名1,typename 类型名2 ...>
template <typename T>
void Swap(T& a, T& b) {T tmp = a;a = b;b = tmp;
}
分析:
1. template是定义模板的关键字,<>内部用于写类型参数,typename就是用于定义模拟类型的关键字,T就是类型名(类型名的命名方式和变量名的命名方式是一样的,只是习惯使用T,T1等)。
我们定义了模板之后,就可以在下面的函数实现中使用定义的模板类型T了。 这个T可以替换成任意的类型。
2. 定义模板时,<>中的类型参数可以有多个。
template <typename T,typename T2>
void printS(T& a,T2& b) {cout << a << endl;cout << b << endl;
}int main(void) {int a = 10;float b = 20.5f;printS(a, b);system("pause");return 0;
}
3. 我们也可以先写函数声明再写函数定义,但是,必须在函数声明和定义前都用该加上模板定义。
template <typename T,typename T2>
void printS(T& a, T2& b);int main(void) {int a = 10;float b = 20.5f;printS(a, b);system("pause");return 0;
}template <typename T, typename T2>
void printS(T& a, T2& b) {cout << a << endl;cout << b << endl;
}
函数调用:
对于函数模板,调用函数有两种方式。
1. 隐式类型参数调用, 调用printS函数: printS(a,b); 编译器会根据我们传入实参的类型,自动将虚拟类型,转换为实参的类型。
2. 显示类型参数调用, 调用printS函数: printS<int,float>(a,b); 我们通过<>中的类型,指定函数模板中虚拟类型指代的具体类型,(根据传入类型的顺序,实例化对应虚拟类型)。
注意:
定义模板时, 我们会使用到<>,<>和()是类似的。只不过<>中写的是类型参数,()中写的是数据参数。在模板定义时, <>中声明类型形参,()中声明数据形参。
在函数调用时,数据形参的个数有几个,我们就需要传入几个数据实参(使用()传),这样才能正常的调用函数。 类型形参也是类似的,我们声明多少个类型形参,在调用函数的时候,就需要传入多少个类型实参(就是具体的类型,使用<>传),否则会报参数不匹配的问题。
只不过在一般函数调用的时候,会根据我们传入的实参的类型,编译器会自动实例化声明的虚拟类型。(当然也是同理的,如果有两个虚拟类型,自然需要传入两种类型的数据)
简单来说,<>和()中都是参数,我们在调用的时候,需要传入对应个数的实参才行。
// 定义
template <typename T>
void Swap(int& t1, int& t2) {int tmp = t1;t1 = t2;t2 = tmp;
}// 调用
Swap<int>(i1, i2); // 定义
template <typename T,typename T1>
void Swap(int t1[], int t2[], int len) {// 遍历互换for (int i = 0; i < len; i++) {int tmp = t1[i];t1[i] = t2[i];t2[i] = tmp;}
}// 调用
Swap<int,float>(arr1, arr2, len);
上面代码中,即使我们在实现中没有使用定义的虚拟类型。但是我们在<>中声明了类型。就需要在函数调用的时候使用<>显示传入相应的类型。
注意: 只有参数使用了相应的模板类型,编译器才能在传参中自动实例化虚拟类型。但是只能实例化参数中使用的虚拟类型。没有使用的,还是需要使用<>传入。
template <typename T,typename T1>
void Swap(T t1[], T t2[], int len) {// 遍历互换for (int i = 0; i < len; i++) {T tmp = t1[i];t1[i] = t2[i];t2[i] = tmp;}
}// 调用
Swap<int,float>(arr1, arr2, len);
代码中我们即使通过参数实例化了T,但是T1并没有被实例化,所以我们需要显示传入类型实例化T2,但是我们传入时,必须按照声明类型参数的格式进行传参。所以<>中需要传入两个类型分别实例化T1,T2。
怎么实现:
那么模板到底是怎么能够实现替换任意类型的呢?
我们前面说到,在调用模板函数的时候,编译器会根据参数的类型自动转换虚拟类型。 其实模板就是这样,根据我们传入参数的类型,或者传入的类型参数(<>中的),编译器会在内部实现一个相应的函数,然后处理相应的数据。
比如:
template <typename T>
void Swap(T& a, T& b) {T tmp = a;a = b;b = tmp;
}int main(void) {int i1 = 10;int i2 = 20;Swap(i1, i2);/*i1和i2是int类型,编译器会自己转化为一个函数void Swap(int& a, int& b) {int tmp = a;a = b;b = tmp;}*/float f1 = 10.1f;float f2 = 20.1f;Swap(f1, f2);/*f1和f2是float类型,编译器会自己转化为一个和上面同名的Swap重载函数。void Swap(float& a, float& b) { // 参数不同float tmp = a;a = b;b = tmp;}*/system("pause");return 0;
}
从代码中,注释可以看出来,编译器会根据我们传入的类型,根据函数模板,将相应的虚拟类型替换成我们传入的类型,实现一个相应的函数重载。然后再去调用实现相应的功能。
模板函数:
怎么实现中我们说到了,在内部编译器会根据模板实现具体的处理函数。这些编译器实现的处理函数就是模板函数。