zoukankan      html  css  js  c++  java
  • 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 }
  • 相关阅读:
    还是java中的编码问题
    java restful api
    编码方式
    LinkedHash
    Zoj 2562 More Divisors (反素数)
    spark复习总结03
    spark复习总结02
    spark复习总结01
    使用二进制解决一个字段代表多个状态的问题
    spark性能调优05-troubleshooting处理
  • 原文地址:https://www.cnblogs.com/xfxu/p/4001250.html
Copyright © 2011-2022 走看看