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('\n');

    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;
}

    

 

posted @ 2018-11-20 16:32  博观&约取  阅读(233)  评论(0编辑  收藏  举报