• 1. 函数模板一


     1. 函数模板示例:

    #include <iostream>
    using namespace std;
    
    //add函数 CPP中是函数的重载
    /*
    int add(int a, int b)
    {
        return a + b;
    }
    char add(char a, char b)
    {
        return a + b;
    }
    double add(double a, double b)
    {
        return a + b;
    }
    */
    
    template<class T>
    T add(T a, T b)
    {
        return a + b;
    }
    
    int main()
    {
        cout << add(1, 2) << endl;        //3
        cout << add('1', '2') << endl;    //c    '1'->48 '2'->49 ==>99(c)
    
        system("pause");
        return 0;
    }

        

      1.1 若程序变为如下:

    #include <iostream>
    using namespace std;
    
    //add函数 CPP中是函数的重载
    int add(int a, int b)
    {
        cout << "int:";
        return a + b;
    }
    
    /*
    char add(char a, char b)
    {
        return a + b;
    }
    double add(double a, double b)
    {
        return a + b;
    }
    */
    
    template<class T>
    T add(T a, T b)
    {
        cout << "T:";
        return a + b;
    }
    
    int main()
    {
        cout << add(1, 2) << endl;        //3        原生函数优先于模板函数
        cout << add('1', '2') << endl;    //c    '1'->48 '2'->49 ==>99(c)
    
        system("pause");
        return 0;
    }

        

      1.2 明确模板数据类型(强行调用模板):

    #include <iostream>
    using namespace std;
    
    //add函数 CPP中是函数的重载
    int add(int a, int b)
    {
        cout << "int:";
        return a + b;
    }
    
    /*
    char add(char a, char b)
    {
        return a + b;
    }
    double add(double a, double b)
    {
        return a + b;
    }
    */
    
    template<class T>
    T add(T a, T b)
    {
        cout << "T:";
        return a + b;
    }
    
    int main()
    {
        //cout << add(1, 2) << endl;        //3        原生函数优先于模板函数
        cout << add<int>(1, 2) << endl;    //明确指定调用模板类型
        cout << add('1', '2') << endl;    //c    '1'->48 '2'->49 ==>99(c)
    
        system("pause");
        return 0;
    }

        

      1.3 模板特性:调用才编译,不调用不编译

    #include <iostream>
    using namespace std;
    
    //add函数 CPP中是函数的重载
    int add(int a, int b)
    {
        cout << "int:";
        return a + b;
    }
    
    /*
    char add(char a, char b)
    {
        return a + b;
    }
    double add(double a, double b)
    {
        return a + b;
    }
    */
    
    template<class T>
    T add(T a, T b)
    {
        cout << "T:"    //去掉了分号";",编译是否成功呢?
        return a + b;
    }
    
    int main()
    {
        //cout << add(1, 2) << endl;        //3        原生函数优先于模板函数
        cout << add<int>(1, 2) << endl;    //明确指定调用模板类型
        cout << add('1', '2') << endl;    //c    '1'->48 '2'->49 ==>99(c)
    
        system("pause");
        return 0;
    }

        此时调用了模板,编译不通过:

        

    #include <iostream>
    using namespace std;
    
    //add函数 CPP中是函数的重载
    int add(int a, int b)
    {
        cout << "int:";
        return a + b;
    }
    
    /*
    char add(char a, char b)
    {
        return a + b;
    }
    double add(double a, double b)
    {
        return a + b;
    }
    */
    
    template<class T>
    T add(T a, T b)
    {
        cout << "T:"    //去掉了分号";",编译是否成功呢?
        return a + b;
    }
    
    int main()
    {
        //cout << add(1, 2) << endl;        //3        原生函数优先于模板函数
        //cout << add<int>(1, 2) << endl;    //明确指定调用模板类型
        //cout << add('1', '2') << endl;    //c    '1'->48 '2'->49 ==>99(c)
    
        system("pause");
        return 0;
    }

        没有调用模板,编译通过:

        

    2. 模板接口:

    #include <iostream>
    using namespace std;
    
    void show(int num)
    {
        cout << num << endl;
    }
    void show1(int num)
    {
        cout << num + 1 << endl;
    }
    
    //泛型接口:传递任何数据类型,传递任何函数指针都可以
    template<class T,class F>    //原则上T代表数据类型,F代表函数
    void run(T t,F f)
    {
        f(t);
    }
    
    int main()
    {
        run(10, show);
        run(10, show1);
    
        system("pause");
        return 0;
    }

        

      2.1 数据类型改变,对接口没有影响:

    #include <iostream>
    using namespace std;
    
    void show(int num)
    {
        cout << num << endl;
    }
    void show1(double num)    //改变数据类型
    {
        cout << num + 1 << endl;
    }
    
    //泛型接口:传递任何数据类型,传递任何函数指针都可以
    template<class T,class F>    //原则上T代表数据类型,F代表函数
    void run(T t,F f)
    {
        f(t);
    }
    
    int main()
    {
        run(10, show);
        run(10.1, show1);
    
        system("pause");
        return 0;
    }

        

      2.2 模板嵌套使用:

    #include <iostream>
    using namespace std;
    
    void show(int num)
    {
        cout << num << endl;
    }
    void show1(double num)    //改变数据类型
    {
        cout << num + 1 << endl;
    }
    
    template<class T>
    void showit(T num)
    {
        cout << num << endl;
    }
    
    //泛型接口:传递任何数据类型,传递任何函数指针都可以
    template<class T,class F>    //原则上T代表数据类型,F代表函数
    void run(T t,F f)
    {
        f(t);
    }
    
    int main()
    {
        //run(10, show);
        //run(10.1, show1);
    
        //run("abc", showit);                //无法确定类型,编译不通过
        run("abc", showit<const char *>);    //指定数据类型
    
        system("pause");
        return 0;
    }

        

      若改为如下:

    int main()
    {
        //run(10, show);
        //run(10.1, show1);
    
        //run("abc", showit);                //无法确定类型,编译不通过
        //run("abc", showit<const char *>);    //指定数据类型
        run("abc", showit<char *>);      //严格的类型匹配(C++是强类型的语言)
    
        system("pause");
        return 0;
    }

        

     3. 可变参数函数模板:

      3.1 类型一致的情况:

    #include <iostream>
    #include <cstdarg>    //可变参数,C语言的可变参数是<stdarg.h>
    using namespace std;
    
    template<class T>
    T add(int n, T t...)    //带三个点"..."表示可变参数 ==>实现n个数相加
    {
        cout << typeid(T).name() << endl;    //先显示出类型
    
        va_list arg_ptr;        //开头的指针 va_list类型为char *
        va_start(arg_ptr, n);    //宏va_start:从arg_ptr开始读取n个数
    
        T res(0);    //初始化结果为0
        for (int i = 0; i < n; i++)
        {
            res += va_arg(arg_ptr, T);    //根据数据类型取出数据
        }
    
        va_end(arg_ptr);    //结束读取    宏va_end
    
        return res;
    }
    
    int main()
    {
        cout << add(4, 1, 2, 3, 4) << endl;        //4个数相加
        cout << add(5, 1, 2, 3, 4, 5) << endl;    //5个数相加
        cout << add(5, 11.1, 12.2, 13.3, 14.4, 15.5) << endl;    //实数
    
        system("pause");
        return 0;
    }

        

       3.2 类型不一致的情况:

    #include <iostream>
    #include <cstdarg>    //可变参数,C语言的可变参数是<stdarg.h>
    using namespace std;
    
    void show()    //下面的递归需要有结束条件,要有函数重载
    {
    
    }
    
    //参数类型不一致,个数不确定的情况
    //typename比class作用域更强,没有类模板可以认为typename=class
    template<typename T,typename...Args>    //typename...Args处理可变参数==>解决任何类型
    void show(T t, Args...args)
    {
        cout << t << endl;        //打印
        show(args...);            //递归 绝对不能省略后面的三个点"args..."
    }
    
    int main()
    {
        show(1, 1.2, "123", 'A');
    
        system("pause");
        return 0;
    }

        

        3.3 函数参数可变参数模板实现printf : <==> 面试中常考

    #include <iostream>
    #include <cstdarg>
    using namespace std;
    
    void show(const char *str)    //递归终止
    {
        cout << str;
    }
    
    template<typename T, typename...Args>
    void show(const char *str, T t, Args...args)
    {
        while (str && *str)    //指针不为空,且字符串没到末尾
        {
            if (*str == '%' && *(str + 1) != '%')    //遇到的%不是连续的,形如%d,%f
            {
                ++str;        //指针后移
                cout << t;    //打印
    
                show(++str, args...);    //继续调用
                return;
            } 
            else
            {
                cout << *str++;    //跳过一个字符
            }
        }
    }
    
    int main()
    {
        printf("%dABCDEFG%s%c%%%fXXXX", 10, "1234", '0', 1234.5);
    
        putchar('
    ');
    
        show("%dABCDEFG%s%c%%%fXXXX", 10, "1234", '0', 1234.5);
    
        system("pause");
        return 0;
    }

        

    4. 模板别名与auto自动推理:

    #include <iostream>
    #include <array>
    using namespace std;
    
    //C++14 auto功能升级,可以任意推理
    //C++11 需要用->指定数据类型
    template<class T1,class T2>
    auto add(T1 t1, T2 t2)->decltype(t1 + t2)
    {
        return t1 + t2;
    }
    
    template<class T> using t = T;        //对模板起别名
    template<class T> using tp = T *;
    //template<class T> typedef T* tp;    //模板的别名不能使用typedef
    template<class T>
    T show(T tx)
    {
        t<int> t1(tx);        //一旦使用别名,必须明确指定类型
        tp<int> tp1(&tx);
    
        cout << t1 << "     " << tp1 << endl;
        return t1;
    }
    
    int main()
    {
        cout << add(1.1, 2) << endl;
        cout << add(1, 2.1) << endl;
    
        int a = 10;
        cout << show(a) << endl;
    
        system("pause");
        return 0;
    }

        

    #include <iostream>
    #include <array>
    using namespace std;
    
    //模板的别名,用别名来优化模板的名称,只能放在类,命名空间,全局;不可以在函数内部
    template<class T> 
    using tencent = array<T, 10>;    //模板的别名,类型不确定,个数确定
    
    template<class T,int n>
    using decs = array<T, n>;        //模板的别名,类型不确定,个数不确定
    
    int main()
    {
        using intarray = array<int, 10>;    //为模板array取了一个别名,类型确定,个数确定
        array<int, 10> myint;
        intarray myint2;
    
        tencent<int> t1 = { 1,2,3,4,5,6,7,8,9,0 };
        for (auto i:t1)
        {
            cout << i << " ";
        }
        cout << endl;
    
        decs<int,10> t2 = { 1,2,3,4,5,6,7,8,9,0 };
        for (auto i : t2)
        {
            cout << i << " ";
        }
        cout << endl;
    
        system("pause");
        return 0;
    }

        

     5. 函数包装器:

    #include <iostream>
    #include <functional>    //函数的命名空间
    using namespace std;
    using std::function;    //函数包装器
    
    void go()
    {
        cout << "go" << endl;
    }
    
    int add(int a, int b)
    {
        return a + b;
    }
    
    int main()
    {
        function<void(void)> fun1 = go;    //function<返回值(参数)> 包装一个函数
        fun1();
    
        function<void(void)> fun2 = []() {cout << "go lambda" << endl; };    //包装一个lambda表达式
        fun2();
    
        function<int(int, int)> fun3 = add;
        cout << fun3(10, 19) << endl;
    
        function<int(int, int)> fun4 = [](int a, int b)->int {return a + b; };
        cout << fun4(10, 19) << endl;
    
        system("pause");
        return 0;
    }

        

    6. 模板元:实现代码加速

    #include <iostream>
    
    //#include <chrono>
    //#include <iomanip> 
    using namespace std;
    
    //台阶问题,递归方法
    int get50(int n)    
    {
        if (n==1)
        {
            return 1;
        }
        else if (n==2)
        {
            return 2;
        }
        else
        {
            return get50(n - 1) + get50(n - 2);
        }
    }
    
    //递归会反复调用,函数等待,返回,浪费很多时间
    //模板元主要实现递归加速,游戏的优化    
    //优点:执行速度快    缺点:编译的时候慢,代码体积会增加(把运行的时间节约在编译的时候)
    template<int N>
    struct data
    {
        enum 
        {    //递归表达式
            res = data<N - 1>::res + data<N - 2>::res
        };
    };
    
    template<>
    struct data<1>
    {
        enum 
        {
            res = 1
        };
    };
    
    template<>
    struct data<2>
    {
        enum
        {
            res = 2
        };
    };
    
    int main()
    {
        
        //int num = 40;
        //cout << data<num>::res << endl;    //模板元只能处理常量
    
        //auto start1 = chrono::high_resolution_clock::now();    //开始时间
    
        cout << data<40>::res << endl;        //模板元代码加速,将运行时间放到了编译中
    
        //auto end1 = chrono::high_resolution_clock::now();    //结束时间
        //__int64 duration = (end1 - start1).count();
        //cout << "程序运行时间:" << setprecision(10) << duration / 1000000000.0 << "s"
        //    << ";  " << duration / 1000000.0 << "ms"
        //    << ";  " << duration / 1000.0 << "us"
        //    << endl;
    
    
        //auto start2 = chrono::high_resolution_clock::now();    //开始时间
    
        cout << get50(40) << endl;        
    
        //auto end2 = chrono::high_resolution_clock::now();    //结束时间
        //__int64 duration2 = (end2 - start2).count();
        //cout << "程序运行时间:" << setprecision(10) << duration2 / 1000000000.0 << "s"
        //    << ";  " << duration2 / 1000000.0 << "ms"
        //    << ";  " << duration2 / 1000.0 << "us"
        //    << endl;
    
        system("pause");
        return 0;
    }

        

  • 相关阅读:
    EF之Model First
    easyui报错 Cannot read property 'length' of null
    EF迁移报错An operation was scaffolded that may result in the loss of data. Please review the migration for accuracy.
    Vue脚手架搭建
    [LeetCode No.20] 有效的括号
    爬虫-给女朋友的每日天气预报
    [LeetCode No.316] 去除重复字母
    [LeetCode No.738] 单调递增的数字
    [LeetCode No.49] 字母异味词分组
    [LeetCode No.34] 在排序数组中查找元素的第一个和最后一个位置
  • 原文地址:https://www.cnblogs.com/si-lei/p/9987698.html
Copyright © 2020-2023  润新知