天天看點

函數模闆初步探究2

參考C++ Primer Plus(中文第五版)P246--258關于函數模闆的材料,總結如下:

結合原書中以下代碼分析:

//程式清單8.13
// twoswap.cpp -- specialization overrides a template
#include <iostream>
template <class Any>
void Swap(Any &a, Any &b);

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

// explicit specialization 
template <> void Swap<job>(job &j1, job &j2);
void Show(job &j);

int main()
{
    using namespace std;
    cout.precision(2);
    cout.setf(ios::fixed, ios::floatfield);
    int i = 10, j = 20;
    cout << "i, j = " << i << ", " << j << ".\n";
    cout << "Using compiler-generated int swapper:\n";
    Swap(i,j);    // generates void Swap(int &, int &)
    cout << "Now i, j = " << i << ", " << j << ".\n";

    job sue = {"Susan Yaffee", 73000.60, 7};
    job sidney = {"Sidney Taffee", 78060.72, 9};
    cout << "Before job swapping:\n";
    Show(sue);
    Show(sidney);
    Swap(sue, sidney); // uses void Swap(job &, job &)
    cout << "After job swapping:\n";
    Show(sue);
    Show(sidney);

    return 0;
}

template <class Any>
void Swap(Any &a, Any &b)    // general version
{
    Any temp;
    temp = a;
    a = b;
    b = temp;
}

// swaps just the salary and floor fields of a job structure

template <> void Swap<job>(job &j1, job &j2)  // specialization
{
    double t1;
    int t2;
    t1 = j1.salary;
    j1.salary = j2.salary;
    j2.salary = t1;
    t2 = j1.floor;
    j1.floor = j2.floor;
    j2.floor = t2;
}

void Show(job &j)
{
    using namespace std;
    cout << j.name << ": $" << j.salary
         << " on floor " << j.floor << endl;
}
           

觀察可知,在僅有的一個twoswap.cpp檔案中,我們在main函數之前聲明了一個正常模闆函數,即:

template <class Any>
void Swap(Any &a, Any &b)
           

還聲明了一個顯示具體化的模闆函數:

// explicit specialization 
template <> void Swap<job>(job &j1, job &j2);
void Show(job &j);
           

在main函數之後,接着定義了這兩個函數。

在這裡,有必要講一下,如果我們在同一個檔案中,定義了三個同名的函數,其中一個是正常模闆函數,一個是顯示具體化的模闆函數,一個是正常的非模闆函數。那麼之間如果存在覆寫的話,優先級是怎樣的呢?

函數模闆初步探究2

 書中告訴了我們答案,它說在C++标準中,具體化的模闆函數将覆寫正常模闆函數,而正常的非模闆函數将覆寫具體化的模闆函數和正常模闆函數。

c++标準還規定了具體化的原型和定義都必須是以template<>打頭,通過名稱來指出類型。

帶代碼中包含模闆本身并不會生成函數定義,它隻是一個用于生成函數定義的方案。編譯器使用模闆為特定類型生成函數定義時,得到的是模闆執行個體(instantiation)。模闆并非函數定義,但是使用特定類型的執行個體是函數定義。這種執行個體化方式被稱為隐式執行個體化(implicit instantiation),就是說:編譯器在遇到模闆函數的聲明和定義代碼時,并沒有給出一個實際的執行個體定義,它隻是獲得了關于一個模闆函數的介紹,而在遇到調用特定類型的模闆函數執行個體時,編譯器才決定以特定類型代替模闆函數的模闆類型參數,并給出特定類型的執行個體化定義。哪照這樣說,如果我們不調用特定類型的模闆函數,模闆也就不會執行個體化了。

但是,現在我們也可以是一個模闆函數顯示執行個體化(explicit instantiation),就是說我們可以直接指令編譯器建立特定的執行個體,方式為:

template <> void 函數名<特定類型>(特定類型參數清單)

如:

template void Swap<job>(job &j1, job &j2)
           

這裡注意,顯示執行個體化和顯示具體化的意思是不一樣的!!!差別在于:

1.顯示具體化(explicit specialization)是針對某種特定類型,需要使用與模闆函數定義中不同的特定算法時,需要對模闆顯示具體化,格式例子如下:

template <> void Swap<job>(job &j1, job &j2)  // explicit specialization 顯示具體化
           

2.顯示執行個體化(explicit instantiation)是實作模闆函數定義的執行個體,格式例子如下:

template  void Swap<job>(job &j1, job &j2)  // explicit instantiation 顯示執行個體化
           

注意顯示具體化的聲明和定義中代碼,在template後面都有一個尖括号<>,而顯示執行個體化都沒有。

實際上,如果對同一個模闆函數的