概念

通用性

具有很强的通用性,节省代码

复用性

保存的模板可以多次使用,节省重复造轮子

差异性

模板需要填写内容,不能直接不加修改的使用

函数模板

C++另一种编程思想是泛型编程,主要利用的技术就是模板
C++提供两种模板机制,函数模板类模板

函数模板的语法

函数模板作用:
建立一个通用函数,其函数返回值类型和形参类型可以不具体制定,用一个虚拟的类型代替。
语法:

  1. template<typename T>
  2. 函数声明或定义

解释:
template —声明创建模板
typename —表面其后面的符号是一种数据类型,可以用class代替
T —通用模板的数据类型,名称可以替换,通常为大写字母

  1. #include <iostream>
  2. using namespace std;
  3. //交换两个整型
  4. void swapInt(int &a, int &b) {
  5. int temp = a;
  6. a = b;
  7. b = temp;
  8. }
  9. //交换两个浮点型
  10. void swapDouble(double &a, double &b) {
  11. double temp = a;
  12. a = b;
  13. b = temp;
  14. }
  15. //函数模板
  16. template <typename T>
  17. void mySwap(T &a, T &b) {
  18. T temp = a;
  19. a = b;
  20. b = temp;
  21. }
  22. void example() {
  23. int a = 1, b = 2;
  24. double c = 1.1, d = 2.2;
  25. //使用常规函数
  26. swapInt(a, b);
  27. swapDouble(c, d);
  28. //第一种,通过自动类型推导的方式让编译器判断类型
  29. mySwap(a, b);
  30. //第二种,显式指定类型
  31. mySwap<double>(c, d);
  32. cout << "a = " << a << endl;
  33. cout << "b = " << b << endl;
  34. cout << "c = " << c << endl;
  35. cout << "d = " << d << endl;
  36. }
  37. int main() {
  38. example();
  39. return 0;
  40. }
  • 函数模板利用关键字 template
  • 使用函数模板有两种方式:自动类型推导、显示指定类型
  • 模板的目的是为了提高复用性,将类型参数化

    注意事项

  • 自动类型推导,必须推导出一致的数据类型T才能使用。

  • 模板必须要确定出T的数据类型,才可以使用。 ```cpp

    include

    using namespace std; //交换两个整型

//注意事项: //1. 自动类型推导,必须推导出一致的数据类型T才可以使用 //2. 末班必须要确定出T的数据类型才可以使用 //交换两个浮点型

//函数模板 template void mySwap(T &a, T &b) { //传入的两个数据类型必须要一致 T temp = a; a = b; b = temp; } template void func() {

} void example() { func(); //即使没有使用T,也必须指定一个数据类型才能使用 int a = 1, b = 2; double c = 1.1, d = 2.2; //使用常规函数 int main() { example(); return 0; }

  1. <a name="5yA7U"></a>
  2. ## 排序示例
  3. 不需要进行函数重载。
  4. ```cpp
  5. #include <iostream>
  6. using namespace std;
  7. //实现一个通用排序函数
  8. // 从大到小
  9. // 选择排序
  10. // 两种数据类型
  11. template <typename T>
  12. void myswap(T &a, T &b) {
  13. T temp = a;
  14. a = b;
  15. b = temp;
  16. }
  17. template <typename T>
  18. void mySort(T arr[], int len) {
  19. for (int i = 0; i < len; i++) {
  20. int max = i;
  21. for (int j = i + 1; j < len; j++) {
  22. //认定的最大值比遍历出的数值要小,说明j下标的元素才是真正的最大值,做交换
  23. if (arr[max] < arr[j]) {
  24. max = j;
  25. }
  26. }
  27. if (max != i) {
  28. //交换逻辑
  29. myswap(arr[max],arr[i]);
  30. }
  31. }
  32. }
  33. //打印数组的末班
  34. template <typename T>
  35. void printArray(T arr[], int len) {
  36. for (int i = 0; i < len; i++) {
  37. cout << arr[i] << " ";
  38. }
  39. cout << endl;
  40. }
  41. void example() {
  42. char charArr[] = "bcaeifdgh";
  43. int lens = sizeof(charArr) / sizeof(char);
  44. mySort(charArr, lens);
  45. printArray(charArr, lens);//会输出a-i的倒序
  46. int numarr[] = { 5,3,6,9,8,6,1,5,4,2,3,5,5,1,0 };
  47. lens = sizeof(numarr) / sizeof(int);
  48. mySort(numarr, lens); //从大到小排序
  49. printArray(numarr, lens);
  50. }
  51. int main() {
  52. example();
  53. return 0;
  54. }

普通函数和函数模板的区别

  1. 普通函数调用时可以发生自动类型转换
  2. 函数末班调用时,如果利用自动类型推导,不会发生饮食类型转换
  3. 如果利用显示指定类型的方式,可以发生隐式类型转换。
    1. template <typename T>
    2. T add(T a, T b) {
    3. return a + b;
    4. }
    5. void example() {
    6. int a = 10, b = 20;
    7. char c = 0;
    8. cout << add(a, b); //不能进行隐式类型转换
    9. // cout << add(a, c); //必须特定的类型
    10. cout << add<int>(a, c); //可以进行隐式类型转换(强制转换)
    11. }
    建议使用制定类型的方式,调用函数模板,防止推导意外。

    普通函数和函数模板的调用规则

  • 如果函数模板和普通函数都可以实现,优先调用普通函数
  • 可以通过空模板参数列表来强制调用函数模板
  • 函数模板可以发生重载
  • 如果函数模板可以产生更好的匹配,优先调用函数模板 ```cpp

void myPrint(int a, int b) { //声明即存在。 cout << “调用普通函数” << endl; } template void myPrint(T a, T b) { cout << “调用模板” << endl; } template void myPrint(T a, T b,T c) { cout << “调用重载的模板” << endl; } void example() { int a = 1, b = 2; //两个都是int类型,普通函数匹配的更好 myPrint(a, b); //即使只声明,没有实现也会优先调用函数模板。 double c = 1.1, d = 2.2; //没有更好的函数可以用来调用,调用模板 myPrint(c, d); myPrint<>(a, b); //空模板参数列表 myPrint(a, b, 100); //模板重载 }

  1. 如果提供了函数模板,则不要使用函数,如果使用函数,则不要使用模板。
  2. <a name="nJIHS"></a>
  3. # 模板的局限性
  4. 模板只能在部分情况简单算法可以,如果传入的是数组,对象等模板就无法通用。<br />**局限性:**
  5. - 模板的通用性并不是万能的
  6. **例如:**
  7. ```cpp
  8. template<class T>
  9. void f(T a, T b)
  10. {
  11. a = b;
  12. }

在上述代码中提供的赋值操作,如果传入的a和b是一个数组,就无法实现了
再例如:

  1. template<class T>
  2. void f(T a, T b)
  3. {
  4. if(a > b) { ... }
  5. }

在上述代码中,如果T的数据类型传入的是像Person这样的自定义数据类型,也无法正常运行
因此C++为了解决这种问题,提供模板的重载,可以为这些特定的类型提供具体化的模板

  1. class Person {
  2. public:
  3. Person(string name, int age) {
  4. this->m_age = age;
  5. this->m_name = name;
  6. }
  7. string m_name;
  8. int m_age;
  9. };
  10. template <typename T>
  11. bool myCompare(T &a, T &b) {
  12. if (a == b)return true; //可以重载==号解决此问题。
  13. else return false;
  14. }
  15. //利用具体化的Person版本实现代码,具体化会优先调用。
  16. //如果不加template,则是普通的函数重载
  17. template <> bool myCompare(Person &a, Person &b) { //具体化的代码
  18. if (a.m_age == b.m_age && a.m_name == b.m_name) return true;
  19. else return false;
  20. }
  21. void example() {
  22. int a = 10;
  23. int b = 20;
  24. bool ret = myCompare(a, b);
  25. if (ret)cout << "==" << endl;
  26. else cout << "!=" << endl;
  27. Person P1("Tom", 10);
  28. Person P2("Tom", 10);
  29. ret = myCompare(P1, P2);
  30. if (ret)cout << "==" << endl;
  31. else cout << "!=" << endl;
  32. }