函数模板

函数模板

  • 泛型编程主要利用的技术就是模板
  • C++提供两种模板机制:函数模板类模板

1.2.1  函数模板语法

函数模板作用:

建立一个通用函数,其函数返回值类型和形参类型可以不具体指定,用一个虚拟的类型来代表

语法:

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

template -- 声明创建模板

typename -- 表面其后面的符号是一种数据类型,可以用class代替

T -- 通用的数据类型,名称可以替换,通常为大写字母

示例代码:

#include <list>
#include <iostream>
using namespace std; 
template<typename T>    //声明一个模板,告诉编译器后面代码中紧跟着的T不要报错, T是一个通用数据类型
void mySwap (T &a, T &b) {
    T temp = a;
    a = b;
    b = temp;
} 
int main()
{
    int a,b;
    a = 10,b = 20;
    //利用函数进行交换
    //1.第一种方式   -- 自动类型推导
    mySwap (a, b); 
    //2.第二种方式   -- 显式指定类型 
    mySwap <int>  (a, b);
    std::cout << "a" << a << std::endl;
    std::cout << "b" << b << std::endl;
    return 0;
}

总结

  • 函数模板利用关键字template 
  • 使用函数模板有两种方式:自动类型推导,显式指定类
  • 模板的目的是为了提高复用性,将类型参数化或者说“泛化”

 

1.2.2 函数模板注意事项

  •  自动类型推导,必须推导出一致的数据类型T才能使用
  • 模板必须要确定出T的准确数据类型,才可以使用
template<typename T>
void test01(){
    std::cout << "测试test01" << std::endl;
}
int main()
{
     test01();     //错误 
     test01<char>();            //正确 
    test02<int>();            //正确
    test03<double>();        //正确
    return 0;
}

可见,必须指定T的数据类型

 

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

  • 普通函数调用时可以发生自动类型转换(隐式类型转换)
  • 函数模板调用时,如果利用自动类型推导, 不会发生隐式类型转换
  • 如果利用显式指定类型的方式,是可以发生隐式类型转换的
 1 #include <iostream>
 2 using namespace std;
 3 int test01 (int a, int b) {
 4     return a + b;
 5 } 
 6 template<typename T>    
 7 T test02 (T a, T b) {
 8     return a + b; 
 9 }
10 int main()
11 {
12     int a = 10;
13     int b = 20;
14     char c = 'c';
15     //普通函数是可以发生隐式转换的 
16     std::cout << "test01(int, int)" << test01 (a,b) << std::endl;
17     std::cout << "test01(int, char)" << test01 (a,c) << std::endl;      
18     //函数模板能否使用,看情况 
19     //1.自动类型推导 无法使用隐式转换 
20     //std::cout << "test02(int, char)" << test02 (a,c) << std::endl;     //报错 
21     //2.显式指定类型可以发生隐式转换 
22     std::cout << "test02(int, char)" << test02<int>(a,c) << std::endl;
23     return 0;
24 }

总结:建议使用显式指定类型的方式,调用函数模板,因为我们自己就可以确定通用类型T

 

1.2.4 普通函数与函数模板的调用规则

调用规则如下:

  • 如果函数模板和普通函数都可以实现,优先调用普通函数
  • 可以通过空模板参数列来强制调用函数模板
  • 函数模板也可以发生重载
  • 如果函数模板可以产生更好的匹配,优先调用函数模板
 1 #include <iostream>
 2 using namespace std;
 3 //普通函数与函数模板调用
 4 void myPrint(int a, int b) {
 5     std::cout << "普通的函数调用" << std::endl;
 6 } 
 7 template<typename T>
 8 void myPrint(T a, T b){
 9     std::cout << "调用的模板" << std::endl;
10 } 
11 
12 template<typename T>
13 void myPrint(T a, T b, T c){
14     std::cout << "调用重载的模板" << std::endl;
15 } 
16 void test01(){
17     int a = 10;
18     int b = 20;
19     //1.优先调用普通函数 
20     myPrint (a,b);
21     
22     //2.通过空模板参数列表,强制调用函数模板
23     myPrint<>(a,b);    //可以发现,即使普通函数和模板函数都存在,但是 仍然只会调用模板函数 
24     
25     //3.重载调用
26     myPrint(a,b,100); 
27     
28     //4.如果函数模板产生更好的匹配,优先调用函数模板
29     char m = 'm';
30     char n = 'n';
31     myPrint (m,n); 
32 }
33 int main()
34 {
35     test01();
36         return 0;
37 }

 总结:既然提供了函数模板,最好就不要提供普通函数,否则容易出现二义性

 

1.2.5 模板的局限性

  有些数据类型是无法直接使用模板的

例如:

1 template<typename T>
2 bool myCompare(T a, T b)
3 {
4        if (a == b)  return true;
5       else return false;
6 }

 在上述代码中,若是普通的数据类型例如int, char, double,还能正常对比,但是如果T是数组或者其他自定义类型呢?

 1 #include <iostream>
 2 #include <string>
 3 using namespace std;
 4 //模板不是万能的,有些特定数据类型,需要用具体化的方式做特殊实现
 5 //对比两个数据是否相等函数
 6 class  Person{
 7 public:
 8     Person (string name, string age) {
 9         this->name = name;
10         this->age = age;
11     }
12     string name;
13     string age;
14 };
15 //普通函数模板 
16 template<class T>
17 bool myCompare(T &a, T &b){
18     if (a == b) 
19         return true;
20     else
21         return false;
22 } 
23 //利用具体化Person的版本来实现代码,具体话优先调用
24 template<> bool myCompare (Person &p1, Person &p2){
25     if (p1.name == p2.name && p1.age == p2.age) 
26         return true;
27     else
28         return false;
29 } 
30 void test02(){
31     Person p1 ("Tom", "10");
32     Person p2 ("Tom", "15");
33     int result = myCompare (p1, p2);
34     if (result)    
35         cout << "p1 == p2" << endl;
36     else
37         cout << "p1 != p2" << endl;
38 }
39 int main()
40 {
41     test02();
42     return 0;
43 }
  • 利用具体化的模板,可以解决自定义类型的通用化
  • 学习模板并不是为了写模板,而是在STL能够运用系统来提供的模板

 

posted @ 2023-07-04 00:06  C++杀我  阅读(26)  评论(0编辑  收藏  举报