模板是泛型編程的基礎
函數模板
模板定義以關鍵字template
開始,后跟一個模板參數列表。這是一個逗號分隔的一個或多個模板參數的列表。用尖括號包圍起來。
模板函數定義的一般形式:
template <class type> ret-tye func-name(parameter list)
{}
模板類型參數前必須使用關鍵字typename
或者class
在這里typename
可以代替class
,兩者等價。
模板參數列表的作用很像函數參數列表
當我們調用一個函數模板時,編譯器通常用函數實參來為我們推斷模板實參。然后用推斷出的模板參數為我們實例化一個特定版本的函數。
除了定義類型參數,我們還可以在模板中定義非類型參數。一個非類型參數表示一個值而非一個類型。當一個模板被實例化時,非類型參數被一個用戶提供的或編譯器推斷出的值(常量表達式)所代替,從而允許編譯器再編譯時實例化模板
例如:我們想要比較兩個字符串常量的大小,由于我們希望能夠比較不同長度的字符串常量,所以在定義的時候使用了非類型的參數。
template<unsigned N,unsigned M>
int compare(const char (&p1)[N],const char (&p1)[M])
{return strcmp(p1,p2);
}//調用
compare("123","789456");
則編譯后編譯器會實例化如下函數:
int compare(const char (&p1)[4],const char(&p2)[7])
{return strcmp(p1,p2);
}
一個非類型參數可以是一個整型或者是一個指向對象或函數類型的指針或者引用,綁定到非類型整型參數的實參必須是一個常量表達式。綁定到指針或者引用非類型參數的實參必須具有靜態的生存期。我們不能用一個普通(非static
)局部變量或者動態對象作為指針或引用非類型模板參數的實參。(雖然我也不是很懂。。。從書上抄來的)
類模板
與函數模板不同之處是編譯器不能為類模板推斷模板參數類型。為了使用類模板,我們必須在模板名后的尖括號中提供額外信息。
類模板:
template <class type> class class-name
{};
編譯器使用顯式模板實參來實例化出特定的類
每個實例形成了獨立的類。互相之間沒有關系。
類模板的成員函數具有和模板相同的模板參數。因此定義在類模板之外的成員函數必須以關鍵字template
開始,后接類模板參數列表。而且,我們還要說明成員屬于哪個類,而模板生成的類必須包含模板實參。當我們定義一個成員函數時,模板實參與模板形參形同。例如:
template <typename T>
ret-type class-name<T>::number-name(parm-list)
{}