zoukankan      html  css  js  c++  java
  • 函数模板

    1.函数模板

        函数模板为通用函数的描叙。

           (1)模板函数不能缩短可执行的程序,仍将使用独立的函数定义。但是模板函数更加简单可靠

           (2)可以重载函数模板,和一般重载一样,要求函数特征标(参数表相异),且能够参数表包含非模板参数如int等

           (3)模板属于编译时多态性,因为编译时自动根据模板生成模板函数。函数重载也是编译多态性。只有虚函数为运行多态。


    2.显式具体化

            即提供模板的函数的某些具体化版本,当编译器找到与函数调用匹配的具体化定义时,将使用该定义而不是模板。例如定义交换函数swap(),交换普通元素和结构体元素,但是要求结构体元素只要求交换部分数据域,如下:

    struct job{
        double salary;
        int rank;	
    }
    
    template<tyname T>
    void swap(const T&,const T&);//通用版本
    template<> void swap<job>(const job&,const job& );//显式具体化版本
    
    
    template<tyname T>
    void swap(const T& a,const T& b)//通用版本
    {
         T temp=a;
    	 a=b;
    	 b=temp;
    }
    template<> void swap<job>(const job& a,const job& b)//显式具体化版本,并不交换所有部分
    {
        double temp=a.salary;
    	 a.salary=b.salary;
    	 b.salary=temp;
    }
    void main(){
        int i=0,j=1;
        swap(i,j);//(i=1,j=0)
    	.......................
    	job a={1000.00,1};
    	job b={2000.00,2}
    	swap(a,b);//(仅仅salary部分交换)
    	......................
    }

    3.编译器选择函数版本的规则

         (1)完全匹配,但是匹配优先度:普通函数>显式具体化函数>模板函数

         (2)提升转换匹配(char short转为int, long转为doubel)

         (3)标准转换匹配(int 到 char, long 到double)

         (4)用户自定义转换。即下文的显式实例化。

             此时应注意,const与非const的区别只存在于指针和引用类型。也就是说,func(int),function(const int)具有相同的匹配等级。若func(int)被最优匹配,则后者也是最优匹配,此时会出现二义性。然后,对于最优匹配的参数表含有指针或者参数的情况,不会出现此种情况。

             编译时,编译器倾向选择最具体且需要最少转换的函数。当然,也可以通过人为指定合适的调用,引导编译器。如:

    template<tyname T>
    T  less(const T& a,const T& b);//#1
    {
         return a<b?:a,b;
    }
    int less(int a,int b)//#2
    {
        return a<b?:a,b;
    }
    main(){
        int i=0,j=1;
    	double m=1.0,n=2.0;
    	
    	less(i,j);//#1
    	less(m,n);//#2
    	less<>(i,j);//#1,“<>”引导编译,要求使用模板函数匹配
    	less<int>(m,n);//#1,显式实例化,m、n被强制转换
    }


    4.非类型参数模板

             只有运行时,细节才被真正的确定。但是在这里,处理的细节不是类型,当要使用基于值的模板时,必须显式地指定这些值,才能够对模板进行实例化。。非类型模板参数(Nontype Template Parameters)只能是整数类型, 指针, 引用。整型必须是常量表达式(constant expression), 指针和引用必须指向静态类型。

    4.1类中的非参数类型模板

        例如定义一个大小事先确定的stack类:

    #include<stdexcept>
    #include<iostream>
    using namespace std;
    
    template<typename T, int MAXSIZE>
    class Stack{
    private:
        T elems[MAXSIZE];
        int numElems;
    public:
        Stack();
        void push(T const&);
        void pop();
        T top() const;
        bool empty() const {
            return numElems == 0;
        }
        bool full() const {
            return numElems == MAXSIZE;
        }
    };
    
    template<typename T, int MAXSIZE>
    Stack<T, MAXSIZE>::Stack():numElems(0) {}
    
    template<typename T, int MAXSIZE>
    void Stack<T, MAXSIZE>::push(T const& elem)
    {
        if(numElems == MAXSIZE) {
            throw out_of_range("Stack<>::push(): stack is full");
        }
        elems[numElems] = elem;
        ++numElems;
    }
    
    template<typename T, int MAXSIZE>
    void Stack<T, MAXSIZE>::pop()
    {
        if(numElems <= 0) {
            throw out_of_range("Stack<>::pop(): stack is empty");
        }
        --numElems;
    }
    
    template<typename T, int MAXSIZE>
    T Stack<T, MAXSIZE>::top() const
    {
        if(numElems <= 0) {
            throw out_of_range("Stack<>::top(): stack is empty");
        }
        return elems[numElems - 1];
    }

    使用:

    #include<iostream>
    #include<vector>
    #include<deque>
    #include<stdexcept>
    #include<string>
    #include<cstdlib>
    #include "stack4.h"
    using namespace std;
    
    
    int main()
    {
        try {
            Stack<int, 20> int20Stack;
            Stack<int, 40> int40Stack;
            Stack<string, 40> stringStack;
            
            int20Stack.push(7);
            cout<<int20Stack.top()<<endl;
            int20Stack.pop();
    
            stringStack.push("hello");
            cout<<stringStack.top()<<endl;
            stringStack.pop();
            stringStack.pop();
        }
        catch(exception const& ex) {
            cerr<<"Exception: "<<ex.what()<<endl;
            //return EXIT_FAILURE;
        }
        
        cin.get();  
        return 0;
    }

    4.2函数中的非类型参数模板

       例如求数组大小模板函数:

    template<unsigned int N,typename T>  
    int coute(T (&a)[N]){  
        return sizeof(a)/sizeof(a[0]);  
    }

    4.3非类型参数模板函数的限制

    (1)只能是int,指针或者引用,不能是float或者double,或者类对象之类。例如:

    template<double VAT>
    double process(double v) //error
    {
        return V * VAT;
    }
    
    template<string name>  //error
    class MyClass {
        ...
    };

      (2)使用全局指针作为模板参数,即extern类型的常量类型:


    5.模板函数的使用要点

          ① 如果在全局域中声明了与模板参数同名的对象函数或类型,则被隐藏。在下面的例子中tmp 的类型不是double 是模板参数Type。

    typedef double Type;
    template <class Type>
    Type min( Type a, Type b )
    {
        // tmp 类型为模板参数 Type,不是全局 double
        Type tmp = a < b ? a : b;
        return tmp;
    }

         ②  在函数模板定义中声明的对象或类型,不能与模板参数同名。

    template <class Type>
    Type min( Type a, Type b )
    {
        typedef double Type; // 错误: 重新声明模板参数 Type
        Type tmp = a < b ? a : b;
        return tmp;
    }

          ③ 返回类型也可是模板类型参数

    template <class T1, class T2, class T3>
    T1 min( T2, T3 );

         ④同一模板参数表必须使用不一样的参数名,但是相异的模板参数表可以使用相同的参数名

    // 错误: 模板参数名 Type 的非法重复使用
    template <class Type, class Type>
    Type min( Type, Type );
     
    //正确: 名字 Type 在不同模板之间重复使用
    template <class Type>
    Type min( Type, Type );
    template <class Type>
    Type max( Type, Type );

       函数模板也可以被声明为inline 或extern 应该把指示符放在模板参数表后面而不是在关键字template 前面。

    template <typename Type> inline
    Type min( Type, Type );




  • 相关阅读:
    Netty实现Http客户端
    Netty实现Http服务端
    Netty实现Tcp客户端
    Netty实现Tcp服务端
    MySQL进阶系列:一文详解explain
    spring boot 获取运行时的yml里的active配置
    eureka 注册中心添加认证
    zuul 负载
    jenkins spring cloud
    秒杀系统如何设计?
  • 原文地址:https://www.cnblogs.com/engineerLF/p/5393031.html
Copyright © 2011-2022 走看看