泛型编程概念:不考虑具体数据类型的编程方式;
函数模板:
1.提供一种特殊的函数可用不同类型进行调用;
2.与普通函数很相似,区别是类型可被参数化;
template <typename T> //template关键字用于声明开始进行泛型编程 void Swap(T &a, T &b) //typename关键字用于声明泛指类型 { T tmp = a; a = b; b = tmp; }
函数模板的应用:
1.自动类型推导调用;
2.具体类型显示调用;
int a = 3; int b = 4; Swap(a,b); //自动类型推导调用 float fa = 5.5; float fb = 8.8; Swap<float>(fa, fb) //具体类型显示调用,用float替换参数类型T
使用演示:
#include <iostream> template <typename T> //交换变量 void Swap(T& a, T& b) { T t; t = a; a = b; b = t; } template <typename T> //将数组内容从小到大排序 void SelectMin(T array[], int size) { for (int i = 0; i < size; i++) { T Min = array[i]; int Index = 1; for (int j = i + 1; j < size; j++) { if (Min > array[j]) { Min = array[j]; Index = j; Swap(array[i], array[Index]); } } } } int main() { int a = 3; int b = 8; Swap(a, b); //自动类型推导 std::cout << "a = " << a << std::endl; std::cout << "b = " << b << std::endl; float fa = 3.4; float fb = 8; Swap<float>(fa, fb); //具体类型显示调用 std::cout << "fa = " << fa << std::endl; std::cout << "fb = " << fb << std::endl; char ca = 'a'; char cb = 'b'; Swap(ca, cb); std::cout << "ca = " << ca << std::endl; std::cout << "cb = " << cb << std::endl; int array[] = {4, 3, 1, 2, 45}; SelectMin(array, 5); for (int i = 0; i < 5; i++) { std::cout << "i = " << array[i] << std::endl; } char array2[] = { 'a', 'f', 'e', 'c', 'b' }; SelectMin(array2, 5); for (int i = 0; i < 5; i++) { std::cout << "i = " << array2[i] << std::endl; } return 0; }
函数模板的深入理解:
-- 编译器并不会把函数模板处理成能够处理任意类型的函数;
--编译器从函数模板通过具体类型产生不同的函数;
--编译器会对函数模板进行两次编译;
--在声明的地方对模板代码本身进行编译
--在调用的地方对参数替换后的代码进行编译
当函数模板遇到函数重载:
--C++编译器优先考虑普通函数;
--如果函数模板可以产生一个更好的匹配,那么选择模板;
--通过空模板实参列表的语法限定编译器只通过模板匹配;
注意事项:
--函数模板不允许自动类型转化;
--普通函数能够进行类型转化;
int Max(int a, int b) //普通函数 { return a > b ? a : b; } template <typename T> //模板函数 T Max(T a, T b) { return a > b ? a : b; } int main() { int a = 4; int b = 8; Max(a,b); //调用普通函数 Max<>(a,b); //空模板实参列表,只能调用函数模板 float fa = 5.5; float fb = 8.8; Max(fa,fb); //调用普通函数会进行类型转换,通过函数模板会产生一个更好的匹配 Max('a',100);//返回结果是调用普通函数a的ASCII码,因为‘a’是字符型,100是整形,与函数模板不匹配
return 0; }
函数模板可以定义多个类型的参数:
template <typename T1, typename T2, typename RT> RT Add(T1 a, T2 b) //RT作为返回类型 { return static_cast<RT>(a+b) } cout<<Add<char, float, double>('a', 100)<<endl; 当声明的类型参数作为返回值类型,无法推导出返回值类型! 即Add('a', 100)这样自动推导调用编译器会报错; 不完美处理方案: template <typename RT, typename T1, typename T2> RT Add(T1 a, T2 b) //RT作为返回类型 { return static_cast<RT>(a+b) } cout<<Add<double>('a', 100)<<endl; //将返回类型放在第一个参数,只显示的列出返回值类型,其它2个参数编译器自动推导