標籤:include 文章 通用
C++中的模版總體可以分為兩大類:模版函數、模版類。本篇文章先寫模版函數,接下來會介紹模版類。
定義:模版函數是通用的函數描述,也就是說它們使用通用類型來定義,其中的通用類型可用具體類型替換。
代碼執行個體:
650) this.width=650;" src="/img/fz.gif" alt="複製代碼" style="border:none;" />
#include <iostream>//模版函數的聲明template<typename T>void Swap(T& a,T& b);int main(){ int i = 10; int j = 20; std::cout<<"i=" << i << "," << "j=" <<j; Swap(i,j);//產生 void Swap(int &,int&); std::cout<<"i=" << i << "," << "j=" <<j; double x = 11.5; double y = 19.5; std::cout<<"x=" << x << "," << "y=" <<y; Swap(x,y);//編譯器產生 void Swap(double &,double&); std::cout<<"x=" << x << "," << "y=" <<y; return 0;}//模版函數的定義template<typename T>void Swap(T& a,T& b){ T temp; temp = a; a = b; b = temp;}
650) this.width=650;" src="/img/fz.gif" alt="複製代碼" style="border:none;" />
以上執行個體為最簡單的函數模版執行個體,編譯器會根據具體使用的類型產生相對應的函數。
重載的模版:
需要多個對不同的類型使用同一演算法時可使用模版,如上代碼所示。但是並非所有的類型都使用相同的演算法。為滿足這種需求,可以像重載常規函數定義那樣重載模版定義。和重載常規函數一樣,重載函數的特徵表必須不同。代碼執行個體如下:
650) this.width=650;" src="/img/fz.gif" alt="複製代碼" style="border:none;" />
#include <iostream>//模版函數的聲明template<typename T>void Swap(T& a,T& b);const int iCount = 5;template<typename T>void Swap(T* a,T*b,int n);int main(){ int i = 10; int j = 20; std::cout<<"i=" << i << "," << "j=" <<j; Swap(i,j);//產生 void Swap(int &,int&) std::cout<<"i=" << i << "," << "j=" <<j; double x = 11.5; double y = 19.5; std::cout<<"x=" << x << "," << "y=" <<y; Swap(x,y);//編譯器產生 void Swap(double &,double&); std::cout<<"x=" << x << "," << "y=" <<y; int d[iCount] = {0,1,2,3,4}; int e[iCount] = {5,6,7,8,9}; Swap(d,e,iCount);//匹配新的模版,進行數組的交換 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){ for (int i=0;i<iCount;++i) { T temp; temp = a[i]; a[i] = b[i]; b[i] = temp; }}
650) this.width=650;" src="/img/fz.gif" alt="複製代碼" style="border:none;" />
如上代碼新增了一個模版,用於交換兩個數組中的元素,原來的模版特徵標為(T&,T&),新模版的特徵標為(T[],T[]),int)。注意,在後一個模版中,最後一個參數的類型為具體類型(int),而不是通用類型,並非所有的模版參數都必須是模版參數類型。
顯示具體化:
對於給定的函數名,可以有非模版函數,模版函數和顯示具體化模版函數以及它們的重載版本。
顯示具體化的原型和定義應該以template<>打頭,並通過名稱來指出類型。
具體化將覆蓋常規模版,而非模版函數將覆蓋具體化和常規模版。
下面是用於交換Job結構的非模版函數,模版函數和具體化的原型。
void Swap(job &,job&);//非模版函數
template <typename T>
void Swap(T&,T&);//模版函數
template <> void Swap<job>(job&,job&);//顯示具體化函數,其中Swap後的job參數可去掉,則函數簽名為template <> void Swap(job&,job&);
前面指出,如果有多個原型,編譯器在選擇原型時,非模版將優先於顯示具體化和模版版本,而顯示具體化將優先於使用模版產生的版本。
如下面的調用:
double u,v;
Swap(u,v);//使用通用的模版
job a,b;
swap (a,b)//使用顯示具體化版本。
執行個體化和具體化:
為了進一步瞭解模版,必須理解術語執行個體化和具體化。記住,在代碼中包含函數模版本身並不會產生函數的定義,它只是一個用於產生函數定義的方案。編譯器使用模版為特定類型組建定義時,得到的是模版執行個體(instantiation)。例如:函數調用Swap(i,j),使編譯器產生一個Swap()的一個執行個體,該執行個體使用int類型。模版並非函數定義,但使用int的模版執行個體是函數定義。這種執行個體化方式被稱為隱式執行個體化,因為編譯器之所以知道需要定義,是由於程式調用Swap()時提供了int參數。
現在編譯器還可以允許顯示執行個體化,這意味著可以直接命令編譯器產生特定的執行個體,如Swap<int>。其句法是,聲明所選的種類-用<>符號指示類型,並在聲明前加上關鍵字template:
template void Swap<int>(int,int);//顯示執行個體化
實現了這種特性的編譯器在看到上述聲明後,將使用Swap()模版產生一個int類型的執行個體。
與顯示執行個體化不同的是,顯示具體化使用下面兩個等價聲明的之一:
template <> void Swap<int>(int,int);
template <> void Swap(int,int);
區別在於,這些聲明的意思是”不要使用Swap()模版來產生函數定義,而應該使用獨立的、專門的函數定義顯示為int類型產生函數定義。
注意:試圖在一個編程單元中使用同一種類型的顯示具體化與顯示執行個體化將出錯。
C++模版函數