函數模板

1、模板

使用泛型來定義函數,其中的泛型可以用具體的數據類型(比如int或double)替換。通過將數據類型作爲參數傳遞給模板,可使編譯器生產該類型的函數。

1.1、爲何需要函數模板

如果要交換兩個int類型,則可以定義一個函數,如果要交換double類型,則可以定義另外一個函數,如果要交換float類型,則可以定義第三個函數,但是這樣顯得很複雜。

函數模板可以將數據類型作爲參數

template <typename AnyType>
void swap(AnyType &a,AnyType &b){
    AnyType temp;
    temp = a;
    a = b;
    b = temp;
}

1.2、實例

#include <iostream>
template <typename T>
void swap(T &a,T &b);
int main(int argc , char** argv){
    using namespace std;
    int i = 10 , j = 20;
    cout << "i = " << i << ",j = " << j << endl;
    cout << "Using compiler generated int swapper\n";
    swap(i,j);//實際生成一個void swap(int &x,int &y);
    cout << "Now i = " << i << ",j = " << j << endl;

    double x =24.5 ,y = 30.2;
    cout << "x = " << x << ",y = " << y << endl;
    swap(x,y);//實際生成一個void swap(double &x,double &y);
    cout << "Now x = " << x << ",y = " << y << endl;
    return 0;
}

template <typename T>
void swap(T &a, T &b){
    T temp;
    temp = a;
    a = b;
    b = temp;
}

1.3、模板使用原理

  1. 第一行template指出建立一個模板。關鍵字template和typename不可缺少。
  2. 模板不創建實際函數,只是告訴編譯器如何定義函數,需要交換int的函數時,編譯器將按照模板創建這樣的函數,並用int代替AnyType。
  3. 函數模板並不減少可執行程序,可執行程序中不包含任何模板,模板只是給編譯器看的,告訴編譯器如何生產函數。
  4. 在可執行程序中,使用手動定義函數和使用模板都是一樣的,但是對於程序員而言,減少了代碼量,方便寫代碼。這也是最大的優點。

2、重載的模板

2.1、區分重載和函數模板的意義

函數模板:對不同的數據類型,要使用相同的算法,比如對於double和int的交換,都使用swap算法。
函數重載:要使用不同的算法,調用相同的函數名。
重載的模板:當多個數據類型使用同種算法時,可使用模板,但是並非所有數據類型都使用相同算法,這時必須重載,也就是重載模板。是模板和重載結合。調用相同的函數名,使用不同算法,處理不同數據類型。

2.2、模板,重載,重載模板三者實例

舉例:
比如要交換int類型,或者double類型,就可以使用模板,定義函數swap,但是如果要交換一個int數組,那麼交換int的算法則不能應用在交換數組上了,因此可以進行重載swap;但是數組可能是int,也可能是double,因此這時可以使用重載模板。

#include <iostream>
template <typename T>       //聲明一個模板
void swap(T &a , T &b);

template <typename T>       //聲明一個重載模板,特徵標不同
void swap(T *a , T *b , int n);
void show(int a[]);
const int lim = 8;

int main(int argc , char** argv){
    using namespace std;
    int i = 10 , j = 20;
    cout << "i = " << i << ",j = " << j << endl;
    cout << "Using compiler generated int swapper\n";
    //實際生成一個void swap(int &x,int &y);
    swap(i,j);
    cout << "Now i = " << i << ",j = " << j << endl;

    double x =24.5 ,y = 30.2;
    cout << "x = " << x << ",y = " << y << endl;
    //實際生成一個void swap(double &x,double &y);
    swap(x,y);
    cout << "Now x = " << x << ",y = " << y << endl;

    int d1[lim] = {0,4,6,3,2,6,8,1};
    int d2[lim] = {6,3,8,5,2,6,8,1};
    show(d1);
    show(d2);
    //匹配重載模板
    swap(d1 , d2 , lim);
    show(d1);
    show(d2);
    return 0;
}

template <typename T>
void swap(T &a, T &b){
    T temp;
    temp = a;
    a = b;
    b = temp;
}

template <typename T>
void swap(T a[] , T b[] , int n){
    T temp;
    for(int i = 0; i < n ; i++){
        temp = a[i];
        a[i] = b[i];
        b[i] = temp;
    }
}

void show(int a[]){
    using namespace std;
    for(int i=0 ; i < sizeof(a) ; i++){
        cout << a[i] << " ";
    }
    cout << endl;
}

3、模板侷限性

雖然使用模板就是爲了針對不同的數據類型,但是某些特殊的類型,則可能無法處理。比如定義一個模板swap,可以處理int,double,float,但是不能處理數組,struct,等。

4、顯示具體化

4.1、顯示具體化的意義

要交換int或double類型,可以建立一個swap交換模板,但是如果類型是struct,則這種算法不適用。上面講過使用重載模板,可以調用相同的函數名,使用不同的算法,但是重載模板必須是函數特徵標不同,也就是函數參數個數不同。這對於swap的兩個struct並不合適。

其實swap交換int和double,以及struct,參數個數都是2個,參數類型都是模板的typename T,因此不適合重載。而交換struct只不過是swap交換模板的一個特例。實現這個特例就用函數模板顯示具體化。

4.2、第三代具體化

(1)對於一個同名的函數,可能最多有以下的幾類函數:常規實現函數,模板顯示具體化,模板函數,重載模板。
(2)顯示具體化的原型和定義應以template <>開頭,並通過名稱指定類型。
(3)當實現了上述4類同名函數時,具體調用哪個函數,按照下面優先原則:常規函數 > 模板顯示具體化 > 模板函數 。重載的模板因爲參數個數不同,不同其他三個比較。

struct job{
    char name[40];
    double salary;
    int floor;
};

//常規實現函數
void swap(job &a , job &b);

//函數模板
template <typename T>
void swap(T &a , T &b>

//模板顯示具體化
template <> void swap<job>(job &a , job &b);

//模板重載
template <typename T>
void swap(T &a , T &b , int n);

4.3、顯示具體化實例

#include <iostream>
template <typename T>
void swap(T &a , T &b);
struct job{
    char name[40];
    double salary;
    int floor;
};
template <> void swap<job>(job &a , job &b);
void show(job &x);

int main(int argc , char** argv){
    using namespace std;
    cout.precision(2);
    cout.setf(ios::fixed,ios::floatfield);
    int i = 10 , j = 20;
    cout << "i,j=" << i << "," << j << endl;
    cout << "Using comiler-generated int swapper" << endl;
    swap(i , j );
    cout << "Now i,j=" << i << "," << j << endl;

    job sue = {"Su" , 7300.2 , 7};
    job Mik = {"Mik" , 4566.3 , 6};
    cout << "Before job swapping " << endl;
    show(sue);
    show(Mik);
    swap(sue , Mik);
    cout << "After job swapping \n" ;
    show(sue);
    show(Mik);
    ruturn 0;
}
template <typename T>
void swap(T &a , T &b){
    T temp;
    temp = a;
    a = b;
    b = temp;
}

template <> void swap<job>(job &x , job &y){
    double t1;
    int t2;
    t1 = x.salary;
    x.salary = y.salary;
    t.salary = t1;
    t2 = x.floor ;
    x.floor = y.floor;
    y.floor = t2; 
}

void show(job &x){
    using namespace std;
    cout < x.name << ":" <<x.salary << "on floor" << x.floor << endl;
}
發佈了50 篇原創文章 · 獲贊 3 · 訪問量 6萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章