本博文主要讨论函数模板及其简单应用。
1)、作用:函数模板可以看做是一种代码产生器,往里面放入具体的类型,得到具体化的函数。
2)、编译(分为两步):
a):实例化之前,先检查模板本身语法是否正确;
b):根据 函数调用调用 ,先去实例化模板代码,产生具体的函数。
也就是说, 没有函数调用,就不会实例化模板代码,在目标文件obj中找不到模板的痕迹。
3):优缺点
模板的缺点是代码膨胀,编译速度慢,而优点是运行速度快。
一、函数模板:
1)、简单操作,代码实现如下:
1 #include2 #include 3 #include 4 using namespace std; 5 6 template 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; //ok17 18 cout << ::max(5.5, 7.8) << endl; //ok19 20 string s1 = "hello"; 21 string s2 = "world";22 cout <<::max(s1, s2)<< endl; //ok23 24 //cout << ::max("hello", "worldd");//error char[6],char[7] 25 //虽然都是字符数组,但是长度也是参数的一部分,故两者不是同一类型26 27 //cout << ::max(3, 4.5) << endl;//error28 //会发生编译错误,因为编译器推断第一个类型为int,第二个为double,没有一个模板符合这个要求,这样就会发生强制转换而产生一个局部的中间变量。这个变量的引用作为return的返回值;即此时我们引用了一个局部变量,这时会产生错误. 29 //修改办法1:30 cout <<::max (3, 6.5) << endl;31 cout << ::max(3, static_cast (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 #include2 #include 3 #include 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 14 const T *max(const T *a, const T *b)15 {16 cout <<"num.4" < *b ? a:b ;18 }19 20 template 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 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 137 cout <<::max(7.0, 43.6) << endl; //238 cout <<::max('a','b') << endl;//2 char39 cout <<::max(7, 42) << endl;//240 cout <<::max<>(7,42) << endl; //2 特定模板41 cout << ::max (7,42)<< endl;//242 cout <<::max('a', 43.7)<
3)、值传递与引用传递的区别:
a):值传递与引用传递对于形参而言,本质区别在于是否产生了局部变量;
b):对于返回值而言,其区别在于, 返回时 是否产生了 临时变量。
c): 对于非引用类型 的参数, 在实参演绎的过程中,会出现 从数组衰退成指针(decay),从而丢失长度信息;而引用类型 则不会引发 衰退 decay。
在模板函数重载中, 不要混合使用值传递和引用传递,而且要尽可能使用引用。
示例代码及注释如下:
1 #include2 #include 3 #include 4 #include 5 using namespace std; 6 7 //传引用 8 template 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 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 #include2 #include 3 #include 4 using namespace std; 5 6 template 7 T max(T a, T b) //值传递-->退化成指针,返回得到是两个指针地址的较大者 8 { 9 return a > b ? a : b;10 }11 12 template 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");//error24 ::max("apple", s);25 26 return 0;27 }