zoukankan      html  css  js  c++  java
  • (三)c++模板函数与函数模板详解

    1、模板函数与函数模板的区别

    模板函数:根据模板写出来的函数。

    函数模板:以后函数实例化都是根据这个模板进行的。

    #include <iostream>
    using namespace std;
    
    // T Max(T a, T b) 函数模板
    template<typename T>
    T Max(T a, T b)
    {
            return a > b ? a : b;
    }
    
    int main()
    {
            cout<<Max<int>('a', 8)<<endl;   // Max<int>('a', 8) 模板函数
            cout<<Max(7, 8)<<endl;  // Max(7, 8) 模板函数 
            return 0;
    }
    

      

    2、函数模板深入理解

    (1)编译器从函数模板通过不同类型产生不同函数

    (2)编译器会对函数模板进行两次编译

      [1] 对模板代码本身进行编译

      [2] 对参数替换后的代码进行编译

    (3)注意事项

      [1] 函数模板本身不允许隐式类型转换

      [2] 自动推导类型时,必须严格匹配

      [3] 显式类型指定时,能够进行隐式类型转换

    #include <iostream>
    using namespace std;
    
    template<typename T>
    T Max(T a, T b)
    {
            return a > b ? a : b;
    }
    
    int main()
    {
            cout<<Max(7, 8)<<endl; // 可自动推导类型为int
            cout<<Max<int>('a', 8)<<endl; // 两个参数的类型不同,不要隐式转换为int,因为函数模板不允许隐式转换
            return 0;
    }

    3、函数模板的本质

    #include <iostream>
    #include <string>
    using namespace std;
    
    class Test
    {
    private:
            Test(const Test&) {}
    public:
            Test() {}
    };
    
    template <typename T>
    void Swap11(T& a, T &b)
    {
            T c = a;
            a = b;
            b = c;
    }
    
    typedef void (FuncA) (int&, int&);
    typedef void (FuncB) (double&, double&);
    typedef void (FuncC) (Test&, Test&);
    
    int main()
    {
            /* 解析:
            FuncA * pa = Swap11; 
                    编译器自动推导T为int
                    用模板Swap11去出师Pa
                    pa的类型又是 void (FuncA) (int&, int&);
                    因此,编译器会用int去替换T,然后生成一个Swap函数
                    并把指针赋值给pa
            FuncB * pb = Swap11;
                    编译器自动推导T为double
            FuncC * pc = Swap11;
                    编译器自动推导T为test,但是进行T替换时,
                    由于Swap函数内部的T c = a; 
                    会调用Test的拷贝构造函数Test(const Test&) {}
                    但它是私有的,所以编译会出错
            */
    
            FuncA * pa = Swap11;
            FuncB * pb = Swap11;
    
            // 证明pa与pb是不同的两个函数
            cout<<"pa= "<<reinterpret_cast<void*>(pa)<<endl;
            cout<<"pb= "<<reinterpret_cast<void*>(pb)<<endl;
    
            //FuncC * pc = Swap11;
            //cout<<"pc= "<<reinterpret_cast<void*>(pc)<<endl;
            return 0;
    }
    

      

    4、函数模板多参数

    特点:

    【1】无法自动推导返回值类型;

    【2】可以从左向右部分指定类型参数;

    【3】工程中将返回值参数作为第一个类型参数

    #include <iostream>
    #include <string>
    using namespace std;
    
    template <typename T1, typename T2, typename T3>
    T1 Add(T2 a, T3 b)
    {
            cout<<"T1= "<<a<<endl;
            cout<<"T2= "<<b<<endl;
            return static_cast<T1>(a);
    }
    
    int main()
    {
            // T1 = <int> = int , T2 = 0.9 = double , T3 = 0.8 = double
            // <int> 从左向右指定类型(返回值->参数1->参数2) 未指定到的, 自动推导类型
            int a = Add<int>(0.9, 0.8);
            cout<<"返回结果为 "<<a<<endl;
    
            // T2 = <double> = double, T2 = 10 = int, T3 = 1.9 = double
            double b = Add<double, char>('b', 91.2);
            cout<<"返回结果为 "<<b<<endl;
    
            // T3 = <char> = char, T2 = 90 = int, T3 = 9.8 = float 
            char c = Add<char, int, float>(90, 9.8);
            cout<<"返回结果为 "<<c<<endl;
            return 0;
    }
    

      

    5、函数模板重载

    【1】优先匹配普通函数,其次匹配函数模板

    【2】如果函数模板可以产生一个更好的匹配,那么选择模板

    【3】可以通过空模板实参列表,限定只匹配模板

      int a = Max(1,2);  // 优先匹配普通函数

      int b = Max<>(1,2);  // <>空模板实参列表,只能匹配函数模板

    #include <iostream>
    #include <string>
    using namespace std;
    
    template <typename T>
    T Max(T a, T b)
    {
            cout<<"函数模板"<<endl;
            return a>b?a:b;
    }
    
    int Max(int a, int b)
    {
            cout<<"普通函数"<<endl;
            return a>b?a:b;
    }
    
    template <typename T>
    T Max(T a, T b, T c)
    {
            cout<<"---函数模板---"<<endl;
            return Max(Max(a, b), c);
    }
    
    int main()
    {
            int a = 10;
            int b = 88;
            cout<<Max(a, b)<<"
    
    ";
            cout<<Max<>(a, b)<<"
    
    "; // <>限定只能从函数模板去匹配
            cout<<Max(3.8, 4.1)<<"
    
    ";
            cout<<Max(3.8, 4.1, 8.8)<<"
    
    "; // 参数个数匹配
            cout<<Max('u', 8.8)<<"
    
    "; // 不允许隐式转换,所以不会匹配函数模板
            return 0;
    }

    6、总结

    (1)函数模板通过具体类型产生不同的函数

    (2)函数模板可以定义任意多个不同的类型参数

    (3)函数模板中的返回值类型必须是显示指定

    (4)函数模板可以像普通函数一样重载

    参考自大神 https://www.cnblogs.com/5iedu/category/811805.html

    做一个优秀的程序媛
  • 相关阅读:
    Backbone源码解析(六):观察者模式应用
    NodeJs 开发微信公众号(五)真实环境部署
    NodeJs 开发微信公众号(四)微信网页授权
    NodeJs 开发微信公众号(三)微信事件交互
    NodeJs 开发微信公众号(二)测试环境部署
    NodeJs 开发微信公众号(一)准备工作
    Css 动画的回调
    GIT常用命令笔记
    论如何在手机端web前端实现自定义原生控件的样式
    Box-sizing:小身材,大拳头!
  • 原文地址:https://www.cnblogs.com/oytt/p/13852611.html
Copyright © 2011-2022 走看看