C++函數模板的隱式實例化、顯式實例化與顯式具體化

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;
}

運行截圖:

           

在程序運行時匹配模板時,遵循的優先級是:

        具體化模板優先於常規模板,而非模板函數優先於具體化和常規模板。  

相關文章
相關標籤/搜索