C++語法-函數模板

C++語法-函數模板

參考《C++ Primer Plus 第6版》

函數模板定義

一般將模板放在頭文件中,並在需要使用模板的文件中包含頭文件。

函數模板也可以重載,其函數特徵標必須不同。

#include <iostream>

using namespace std;

//定義一個模板,用於交換兩個變量的值
template<typename T>
void Swap(T& x,T& y)
{
    T tmp = x;
    x = y;
    y = tmp;

    cout << " - Template Swap(T&,T&)" << endl;
}


int main(int argc,char** argv)
{
    int a = 3;
    int b = 4;

    cout << " - 0" << endl;
    cout << " a = " << a << endl;
    cout << " b = " << b << endl;

    Swap(a,b);

    cout << " a = " << a << endl;
    cout << " b = " << b << endl;
    
    return 0;
}

 

顯示具體化

當一般的函數模板不能滿足特定需求時,可以通過顯示具體化(explicit specialization)在保證不修改函數參數的情況下滿足條件。

如上例,需要定義一個交換指定類型的具體函數,如下所示:

#include <iostream>
using namespace std;

//定義一個模板,用於交換兩個變量的值
template<typename T>
void Swap(T& x,T& y)
{
    T tmp = x;
    x = y;
    y = tmp;

    cout << " - Template Swap(T&,T&)" << endl;
}

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

void showJob(const Job& j);
template<> void Swap<Job>(Job& jx,Job& jy); //顯示具體化聲明

int main(int argc,char** argv)
{
   Job ja = {"James Bond",1000.0,7};
   Job jb = {"Indianna Smith",1500.0,8};

    showJob(ja);
    showJob(jb);

    Swap(ja,jb);

    showJob(ja);
    showJob(jb);

    return 0;
}

void showJob(const Job& j)
{
    cout << j.name << endl 
        << " -- salary:" << j.salary << endl 
        << " -- floor:" << j.floor << endl;
}

/**
 * 顯示具體化
 * 1. 顯示具體化的原型和定義以template<>開頭;
 * 2. 在函數名後指定參數類型,如Swap<Job>;
 * 3. <Job>也可以省略,爲可選;
 * 4. 具體化優先於常規函數模板
 * */
template<> void Swap<Job>(Job& jx,Job& jy)
{
    cout << "template<> Swap<Job>" << endl;
    double tmp_salary = jx.salary;
    int tmp_floor = jx.floor;
    jx.salary = jy.salary;
    jx.floor = jy.floor;
    jy.salary = tmp_salary;
    jy.floor = tmp_floor;
}
  • 顯示具體化的原型和定義以template<>開頭;

  • 在函數名後指定參數類型,如Swap<Job>

  • <Job>也可以省略,爲可選;

  • 具體化優先於常規函數模板.

 

實例化

函數模板本身並不是函數,也不構成給函數定義。在需要的時候,編譯器使用模板爲特定類型生成函數定義,即得到模板實例(initialization)。在使用常規函數模板時,都會進行實例化,此即隱式實例化(implicit initialization)。除此之外,還可以顯示地進行實例化,即顯示實例化(explicit initialization)。

顯示實例化的做法是在聲明前加關鍵字template,並且用<>符號指定類型:

template void Swap<double>(double&,double&);
  • 與顯示具體化不同的是,顯示實例化前面的關鍵字template後面不跟<>符號,而顯示具體化必須要有<>符號。

  • 顯示具體化必須要有自己的函數定義。

  • 同一個文件中使用同一種類型的顯示具體化和顯示實例將會出錯。

除了聲明顯示具體化外,還可以直接通過使用函數來創建顯示實例化,如下代碼所示:

//...
    double a = 1.2;
    double b = 2.3;
    Swap<double>(a,b); //顯示實例化
    cout << a << " , " << b << endl;
//...

上面的代碼並沒有先聲明顯示實例化。

 

選擇函數版本

優先級排序:

非模板函數 > 具體化 > 常規模板函數

最佳到最差的順序

  1. 完全匹配;

  2. 提升轉換,如char自動轉換爲int;

  3. 標準轉換,如int轉換爲char;

  4. 用戶自定義的轉換,如類聲明中定義的轉換。

兩個函數完全匹配的情況

這種情況下,有時可以完成重載解析:

  • 參數爲指向非const數據的指針和引用優先於指向const指針和引用參數,注意,參數爲指針或者引用;

  • 非模板函數優先於模板函數(包括顯示具體化)。

注意:參數完全匹配的引用版和非引用版,存在二義性。

 

自定義選擇

在模板和函數相同的時候,也能指定調用模板,如下所示,通過在函數名後面使用<>符號即可:

#include <iostream>
#include <functional>

template<typename T>
T lesser(T a,T b)
{
    cout << "template<T>" << endl;;
    return a < b?a:b;
}

//默認對於int類型,選擇此函數
int lesser(int a,int b)
{
    cout << "int lesser" << endl;
    return a < b?a:b;
}

int main(int argc,char** argv)
{
    cout << lesser(3,4) << endl;
    cout << lesser<>(3,4) << endl; //選擇模板,實例化,T爲int;

    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章