C++学习之模板(一) ----函数模板

本博文主要讨论函数模板及其简单应用。

1)、作用:函数模板可以看做是一种代码产生器,往里面放入具体的类型,得到具体化的函数。

2)、编译(分为两步):

a):实例化之前,先检查模板本身语法是否正确;

b):根据 函数调用调用 ,先去实例化模板代码,产生具体的函数。

也就是说, 没有函数调用,就不会实例化模板代码,在目标文件obj中找不到模板的痕迹。

3):优缺点

模板的缺点是代码膨胀,编译速度慢,而优点是运行速度快。

一、函数模板:

1)、简单操作,代码实现如下:

 1 #include <iostream>
 2 #include <string>
 3 #include <vector>
 4 using namespace std;
 5 
 6 template <typename T>
 7 //修改办法2:
 8 //T max(const T &a, const T &b)
 9 const T &max(const T &a, const T &b)
10 {
11     return a > b ? a: b;
12 }
13 
14 int main(int argc, const char *argv[])
15 {
16     cout << ::max(7, 42) << endl; //ok
17 
18     cout << ::max(5.5, 7.8) << endl; //ok
19 
20     string s1 = "hello"; 
21     string s2 = "world";
22     cout <<::max(s1, s2)<< endl; //ok
23     
24     //cout << ::max("hello", "worldd");//error char[6],char[7] 
25     //虽然都是字符数组,但是长度也是参数的一部分,故两者不是同一类型
26     
27     //cout << ::max(3, 4.5) << endl;//error
28     //会发生编译错误,因为编译器推断第一个类型为int,第二个为double,没有一个模板符合这个要求,这样就会发生强制转换而产生一个局部的中间变量。这个变量的引用作为return的返回值;即此时我们引用了一个局部变量,这时会产生错误.   
29        //修改办法1:
30     cout <<::max<int>(3, 6.5) << endl;
31     cout << ::max(3, static_cast<int>(6.5)) << endl;
32     
33     return 0;
34 }

2)、一个非模板函数可以和一个同名的函数模板同时存在;两者可以因为参数不同而构成重载;

模板函数重载时,现则函数版本的一些特点:

a):条件相同时,选择非模板函数;例如 ::max(7,42);

b):在强制类型转化,与可行的实例化模板之间,优先选择实例化模板;例如::max(7.0,43.5),::max(‘a’,‘b’);

c):若实例化版本不可行,则尝试普通函数的转化,例如::max(‘a’。42.7)

d)参数是指针时,优先选择可实例化模板的引用版本,若不存在,则优先选择指针版本;

e):总之,尽可能采用最匹配、开销最小的版本。

示例代码及注释如下:

 1 #include <iostream>
 2 #include <string>
 3 #include <vector>
 4 using namespace std;
 5 
 6 //调用策略--->精准调用
 7 const int &max(const int &a, const int &b)
 8 {
 9     cout << "num.1"<< endl;
10     return a> b? a: b;
11 }
12 
13 template <typename T>
14 const T *max(const T *a, const T *b)
15 {
16     cout <<"num.4" <<endl;
17     return *a > *b ? a:b ;
18 }
19 
20 template <typename T>
21 const T &max(const T &a,const T &b)
22 {
23     cout << "num.2" << endl;
24     return a> b? a: b;
25 }
26 
27 template <typename T>
28 const T &max(const T &a, const T &b, const T &c)
29 {
30     cout << "num.3"<< endl;
31     return ::max(::max(a, b), c);
32 }
33 
34 int main(int argc, const char *argv[])
35 {
36     cout <<::max(7, 42, 68) << endl; //3 1 1
37     cout <<::max(7.0, 43.6) << endl; //2
38     cout <<::max('a','b') << endl;//2 char
39     cout <<::max(7, 42) << endl;//2
40     cout <<::max<>(7,42) << endl; //2 特定模板
41     cout << ::max<double>(7,42)<< endl;//2
42     cout <<::max('a', 43.7)<<endl; //1 强制转换
43     
44     int a = 7;
45     int b = 89;
46     int *p1 = &a;
47     int *p2 = &b;
48     cout << ::max(p1, p2) << endl;//2 传引用,减少开销
49     
50     return 0;
51 }

3)、值传递与引用传递的区别:

a):值传递与引用传递对于形参而言,本质区别在于是否产生了局部变量

b):对于返回值而言,其区别在于, 返回时 是否产生了 临时变量

c): 对于非引用类型 的参数, 在实参演绎的过程中,会出现 从数组衰退成指针decay),从而丢失长度信息;而引用类型 则不会引发 衰退 decay

在模板函数重载中, 不要混合使用值传递和引用传递,而且要尽可能使用引用。

示例代码及注释如下:

 1 #include <iostream>
 2 #include <string>
 3 #include <vector>
 4 #include <string.h>
 5 using namespace std;
 6 
 7 //传引用
 8 template <typename T>
 9 const T &max(const T &a, const T &b)
10 {
11     cout <<"num.1" << endl;
12     return a> b? a: b;
13 }
14 
15 //传值
16 //修改1-->改为传引用
17 //const char *&max(const char *&a, const char *&b)
18 const char *max(const char *a, const char *b)
19 {
20     cout <<"num.2" << endl;
21     return ::strcmp(a, b)> 0? a: b;
22 }
23 
24 //传引用
25 //修改2-->改为传值
26 //const T max(const T &a, const T &b, const T &c)
27 template <typename T>
28 const T &max(const T &a, const T &b, const T &c)
29 {
30     cout <<"num.3" << endl;
31     return ::max(::max(a, b), c);//return 临时变量
32     //这里将临时变量的引用返回出去,可能导致错误
33     //const char*tmp=::max(::max(s1,s2),s3)
34 }
35 
36 int main(int argc, const char *argv[])
37 {
38     cout <<::max(7, 42, 68) << endl;
39 
40     const char *s1 = "beij";
41     const char *s2 = "shangh";
42     const char *s3 = "shenzh";
43     
44     cout <<::max(s1, s2, s3) << endl;
45     
46     return 0;
47 }

decay衰退的简单示例:

 1 #include <iostream>
 2 #include <string>
 3 #include <vector>
 4 using namespace std;
 5 
 6 template <typename T>
 7 T max(T a, T b) //值传递-->退化成指针,返回得到是两个指针地址的较大者
 8 {
 9     return a > b ? a : b;
10 }
11 
12 template <typename T>
13 const T &max(const T &a, const T &b) //传引用
14 {
15     return a > b ? a : b;
16 }
17 
18 int main(int argc, const char *argv[])
19 {
20     string s = "hello";
21 
22     ::max("hello", "world");
23     ::max("apple", "orange");//error
24     ::max("apple", s);
25 
26     return 0;
27 }
原文地址:https://www.cnblogs.com/xfxu/p/4001250.html