1、什麼是實例化和具體化?ios
爲進一步瞭解模板,必須理解術語實例化和具體化。數組
(1)、實例化:在程序中的函數模板自己並不會生成函數定義,它只是一個用於生成函數定義的方案。編譯器使用模板爲特定類型生成函數定義時,獲得的是模板實例。這便是函數模板的實例化。函數
而函數模板實例化又分爲兩種類型:隱式實例化和顯式實例化spa
例如:指針
template < typename T >
void Swap( T &a, T &b )
{
T temp;
temp = a;
a = b;
b = temp;
}
int main(void)
{
int a= 1, b = 2;
Swap(a, b);
Swap<int>(a, b);
return 0;
}blog
能夠發現,在主函數中有兩種Swap函數調用。原型
第一個Swap(a, b)致使編譯器自動識別參數類型生成一個實例,該實例使用int類型,此爲隱式實例化。 編譯器
而第二個Swap<int>(a, b),直接命令編譯器建立特定的int類型的函數實例,用<>符號指示類型,此爲顯式實例化。io
(2)、具體化:即顯式具體化,與實例化不一樣的是,它也是一個模板定義,但它是對特定類型的模板定義。顯式具體化使用下面兩個等價的聲明之一:編譯
template <> void Swap<int>(int &, int &);
template <> void Swap(int &, int &);
能夠發現,顯式具體化聲明在關鍵字template後包含<>。上面聲明的意思是"不要使用Swap()模板來生成函數定義,而應使用專門爲int類型顯式地定義的函數的定義"。這些原型必須有本身的函數定義。
在這裏,有人可能要說了:」明明能夠經過隱式實例化自動生成int類型的函數定義,爲什麼還要弄出一個顯式具體化來弄出另一個模板呢?這不是畫蛇添足嗎?」
我要解釋一下,顯式具體化的主要用途!而在介紹用途以前,咱們先來了解一下普通函數模板的侷限性。
2、模板的侷限性
假設有以下模板函數:
template <typename T>
void fun(T a, T b)
{ ... }
一般,代碼假定可執行哪些操做。例如,下面的代碼假定定義了賦值。
a = b;
可是若是T爲數組,這種假設將不成立!
一樣,下面的語句假設定義了<
if ( a > b )
但若是T爲結構,則該假設便不成立!
另外,爲數組名定義了運算符 > ,但因爲數組名是常量地址,所以它比較的是數組的地址,而這並非咱們所指望的操做。下面的語句假定爲類型T定義了乘法運算符,但若是T爲數組、指針或結構,這種假設便不成立:
T c = a * b;
總之,編寫的模板函數極可能沒法處理某些類型。一般在C++中有一種解決方案是:運算符重載,以便能將其用於特定的結構或類。就是說一個類重載了運算符+以後,使用運算符+的模板即可以處理重載了運算符+的結構。
可是,還有另一種解決方案:爲特定類型提供具體化的模板定義(這就是顯式具體化的主要用途)。
3、顯式具體化
假定定義了以下結構:
struct job
{
char name[40];
double salary;
int floor;
}
另外,假設但願可以交換兩個這種結構的內容。原來的模板使用下面的代碼來完成交換:
temp = a;
a = b;
b = temp;
因爲C++容許將一個結構賦給另外一個結構,所以即便T是一個job結構,上述代碼也可適用。然而,若是隻想交換salary和floor成員,而不交換name成員,則須要使用不一樣的處理代碼。但Swap() 的參數將保持不變(兩個job結構的引用),所以沒法使用模板的重載來提供其餘代碼(模板重載,模板的參數列表必須不一樣)。這時,就得用顯式具體化來實現這個需求。
上面已經介紹過顯式具體化的聲明方式,咱們直接經過代碼實例來看一下:
#include <iostream>
using namespace std;
//job結構
struct job
{
char name[40];
double salary;
int floor;
};
//普通交換模板
template <typename T>
void Swap(T &a, T &b)
{
T temp;
temp = a;
a = b;
b = temp;
}
//job類型的顯式具體化模板
template <> void Swap<job>(job &j1, job &j2)
{
double t1;
int t2;
//交換salary
t1 = j1.salary;
j1.salary = j2.salary;
j2.salary = t1;
//交換floor
t2 = j1.floor;
j1.floor = j2.floor;
j2.floor = t2;
}
int main(void)
{
int inta = 1, intb = 2;
job zhangSan = {"張三", 80000, 6};
job liSi = {"李四", 60000, 4};
cout << "inta = " << inta << " inta = " << intb << endl;
cout << zhangSan.name << " , " << zhangSan.salary << " , " << zhangSan.floor <<endl;
cout << liSi.name << " , " << liSi.salary << " , " << liSi.floor <<endl;
Swap(inta, intb); //編譯器將實例化普通模板的int類型函數
Swap(zhangSan, liSi); //編譯器將實例化顯式具體化模板job類型函數
cout << "\n交換後:\n" << endl;
cout << "inta = " << inta << " inta = " << intb << endl;
cout << zhangSan.name << " , " << zhangSan.salary << " , " << zhangSan.floor <<endl;
cout << liSi.name << " , " << liSi.salary << " , " << liSi.floor <<endl;
return 0;
}
運行截圖:
在程序運行時匹配模板時,遵循的優先級是:
具體化模板優先於常規模板,而非模板函數優先於具體化和常規模板。