函數模板

1.函數模板

    函數模板爲通用函數的描敘。ios

       (1)模板函數不能縮短可執行的程序,仍將使用獨立的函數定義。可是模板函數更加簡單可靠express

       (2)能夠重載函數模板,和通常重載同樣,要求函數特徵標(參數表相異),且可以參數表包含非模板參數如int等數組

       (3)模板屬於編譯時多態性,由於編譯時自動根據模板生成模板函數。函數重載也是編譯多態性。只有虛函數爲運行多態。less


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)徹底匹配,可是匹配優先度:普通函數>顯式具體化函數>模板函數spa

     (2)提高轉換匹配(char short轉爲int, long轉爲doubel)指針

     (3)標準轉換匹配(int 到 char, long 到double)code

     (4)用戶自定義轉換。即下文的顯式實例化。對象

         此時應注意,const與非const的區別只存在於指針和引用類型。也就是說,func(int),function(const int)具備相同的匹配等級。若func(int)被最優匹配,則後者也是最優匹配,此時會出現二義性。而後,對於最優匹配的參數表含有指針或者參數的狀況,不會出現此種狀況。ci

         編譯時,編譯器傾向選擇最具體且須要最少轉換的函數。固然,也能夠經過人爲指定合適的調用,引導編譯器。如:

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 );
相關文章
相關標籤/搜索