• C++函数模板


    C++函数模板

    template<typename T>
    void Swap(T &a ,T &b)
    {
        T temp;
        temp = a;
        a = b;
        b = temp;
    }
    

    在使用模板函数时,编译器根据实际的类型生成相应的函数定义。

    重载的模板

    并非所有的类型都使用相同的算法,可以像重载常规函数那样重载模板函数定义。

    template<typename T>
    void Swap(T &a ,T &b); //#1
    
    template<typename T>
    void Swap(T *a ,T *b,int n);//#2 最后一个参数是具体类型
    
    int main()
    {
        int i =10,j=20;
        Swap(i,j);//使用#1
        
        const int Lim = 8;
        int d1[Lim]={0,1,2,3,4,5,6,7};
        int d2[Lim]={7,6,5,4,3,2,1,0};
        Swap(d1,d2,Lim);//使用#2
    }
    template<typename T>
    void Swap(T &a ,T &b)
    {
        T temp;
        temp = a;
        a = b;
        b = temp;
    }
    
    template<typename T>
    void Swap(T *a ,T *b,int n)
    {
        T temp;
        for(int i=0;i<n;i++)
        {
            temp =a[i];
            a[i]=b[i];
            b[i]=temp;
        }
    }
    

    模板局限性

    某些时候,类型T的相应操作只适用于数组,如果T为结构体则模板函数便不成立

    同样,如if(a>b),如果T为结构,则>便不成立

    解决方案:

    1. 重载运算符号
    2. 为特定类型提供具体化模板定义

    显示具体化

    当编译器找到与函数调用匹配的具体化定义时,将使用该定义,不再寻找模板。

    • 对于给定的函数名,可以有非模板函数、模板函数和显示具体化模板函数以及各自的重载版本。
    • 显示具体化的原型和定义以template<>开头,并通过名称来指出类型
    • 调用顺序是:非模板函数>具体化模板函数>模板函数
    void Swap(job& ,job&);
    
    template <typename T>
    void Swap(T&,T&);
    
    template<> void Swap<job>(job& ,job&);//显示具体化
    //Swap<job>中<job>是可选的,因为函数的参数类型表明,这是job的一个具体化,所以也可以这样写:
    template<> void Swap(job& ,job&);
    

    实例化和具体化

    注意:函数模板并不会生成函数定义,他只是生成一个用于生成函数定义的方案,编译器使用模板为特定的类型生成函数定义时,得到的是模板实例。

    template<typename T>
    void Swap(T &a ,T &b);
    
    int a =10,b=20;
    Swap(a,b);//因为提供了int类型的参数,所以自动生成了int类型的模板实例。这样是==隐式实例化==
    //也可以直接命令编译器创建特定的实例
    //显示实例化
    template void Swap<int>(int &,int &);//使用Swap()模板生成int类型的函数定义
    
    //显示具体化
    template<> void Swap<int>(int& ,int&);
    template<> void Swap(int& ,int&);
    //区别在于:具体化是不使用Swap()模板函数生成函数定义,而是使用专门为int类型显示定义的函数定义
    //简单的理解,具体化是对函数的声明,而实例化是对模板函数的使用
    
    template<typename T>
    T Add(T a,T b)
    {
        return a+b;
    }
    
    int m=6;
    double x=10.5;
    Add<double>(x,m); //与Add(x,m)不匹配,因为一个是int一个是double
    				  //通过Add<double>实例化,可强制将m转为double
    
    //但是同样的对Swap便不能成功,因为Swap中使用的是引用类型
    Swap<double>(m,x);//double& 不能指向int
    
    //使用案例
    template <typename T>
    void Swap(T &,T &);
    
    template<> void Swap<job>(job&,job&);//具体化
    int mian()
    {
        template void Swap<char>(char& ,char&);
        
        short a,b;
        Swap(a,b);//隐式实例化
        
        job n,m;
        Swap(n,m);//显示具体化
        
        char g,h;
        Swap(g,h);//显示实例化
    }
    

    模板函数类型的确定

    template<class T1,class T2>
    void fun(T1 x,T2 y)
    {
        ?type? s=x+y; //因为是模板函数,此时?type?类型不确定
    }
    

    C++11增加decltype关键字

    template<class T1,class T2>
    void fun(T1 x,T2 y)
    {
        decltype(x+y) s=x+y; //s类型与x+y的类型一致
    }
    

    使用decltype(expression) var 的步骤:

    1. 如果expression没有用括号括起来,则var与expression类型相同,包括const等限定符
    double x =5.5;
    double& z =x;
    const double* pd;
    decltype(x) w; //w为double类型
    decltype(z) u; //u为double& 类型
    decltype(pd) v; //v为const double* 类型
    
    1. 如果expression是一个函数调用,则var与返回值类型相同。并不会实际调用函数,编译器通过查看原型来确定返回值类型
    2. 如果expression是一个左值,则var为指向其类型的引用。常见的情况如下:
    double x = 4.5;
    decltype((x)) r = x;//r是double&类型
    decltype(x) r = x;//r是double类型
    
    //括号不会改变expression的值和左值性
    //可理解为加括号仅仅是decltype声明引用的一种方式
    
    1. 如果前3条都不满足,则var与expression类型相同
    int j=3;
    int &k=j;
    int &n=j;
    
    decltype(j+6) x; //x是int
    decltype(k+n) y;//y是int ,虽然k和n是引用,但是k+n不是引用是2个int的和
    

    如果多次声明,可以结合typedefdecltype

    typedef decltype(x+y) xytype;
    xytype z = x+y;
    xytype arr[10];
    

    但是某些需定义返回值类型的函数模板任然不能得到解决,如:

    template<class T1,class T2>
    ?type? fun(T1 x,T2 y) //此时无法确定类型
    {
        return x+y;
    }
    

    C++新增语法auto h(int x,float y) -> double,这称为后置返回类型,auto是一个占位符

    template<class T1,class T2>
    auto fun(T1 x,T2 y)->decltype(x+y) //后置类型使用decltype
    {
        return x+y;
    }
    
  • 相关阅读:
    让人疑惑的STM32F4F7芯片
    设置单元格格式无效,Excel中删除某列的千分位符号
    每日一题 —— LC. 792 匹配子序列的单词数
    美国国家安全实验室员工详细数据在网上泄露
    一维码和二维码图像优化——提高读码率
    【消息队列笔记】chp1-消息队列的使用场景
    JUC线程池
    安全配置错误规避指南
    React面试题总结(二)
    Linux操作-1之内容切割命令cut
  • 原文地址:https://www.cnblogs.com/qsnn/p/16370860.html