C++之模板與泛型編程

定義模板

函數模板

template <typename T>
int compare (const T &v1, const T &v2){
	if (v1 < v2) return -1;
	if (v2 < v1) return 1;
	return 0;
}

當我們調用一個函數模板時,編譯器用函數實參來爲我們推斷模板實參

cout<<compare(1,0)<<endl;

除了定義類型參數,還可以在模板中定義非類型參數一個非類型參數表示一個值而非一個類型。我們通過一個特定的類型名而非關鍵字class或typename來指定非類型參數

</font color=“red”>當一個模板被實例化時,非類型參數被一個用戶提供的或編譯器推斷出的值所代替。這些值必須是常量表達式,從而允許編譯器在編譯時實例化模板。
例如:

template<unsigned N,unsigned M>
int compare(const char (&p1)[N],const char (&p2)[M]){
	return strcmp(p1,p2);
}

編譯器會使用字面常量的大小來代替N和M,從而實例化模板。
在模板定義內,模板非類型參數是一個常量值。在需要常量表達式的地方,可以使用非類型參數,例如,指定數組大小。

編寫泛型代碼的兩個重要原則:

  • 模板中的函數參數是const的引用
  • 函數體中的條件判斷僅使用<比較運算

通過將函數參數設定爲const的引用,我們保證了函數可以用於不能拷貝的類型。大多數類型,包括內置類型和我們已經用過的標準庫類型(除unique_ ptr 和I0類型之外),都是允許拷貝的。但是,不允許拷貝的類類型也是存在的。通過將參數設定爲const 的引用,保證了這些類型可以用我們的compare函數來處理。而且,如果compare用於處理大對象,這種設計策略還能使函數運行得更快。

當編譯器遇到一個模板定義時,它並不生成代碼。只有當我們實例化出模板的一個特定版本時,編譯器纔會生成代碼。當我們使用(而不是定義)模板時,編譯器才生成代碼, .這一特性影響了我們如何組織代碼以及錯誤何時被檢測到。

通常,當我們調用一個函數時,編譯器只需要掌握函數的聲明。類似的,當我們使用一個類類型的對象時,類定義必須是可用的,但成員函數的定義不必已經出現。因此,我們將類定義和函數聲明放在頭文件中,而普通函數和類的成員函數的定義放在源文件中。

模板則不同:爲了生成一個實例化版本,編譯器需要掌握函數模板或類模板成員函數的定義。因此,與非模板代碼不同,模板的頭文件通常既包括聲明也包括定義。

類模板

類模板與函數模板的不同之處是:**編譯器不能爲類模板推斷模板參數類型。**爲了啥用類模板,我們必須在模板名後的尖括號提供額外信息。

類模板與友元

//前置聲明,在Blob中聲明友元所需要的
template <typename> 
class BlobPtr;
template <typename> 
class Blob; // 運算符==中的參數所需要的
template <typename T>
bool operator==(const Blob<T>&const B1ob<T>&) ;
template <typename T> 
class Blob {
	//每個Blob實例將訪問權限授予用相同類型實例化的BlobPtr和相等運算符
	friend class B1obPtr<T>;
	friend bool operator==<T>(const Blob<T>&const Blob<T>&);
};

類模板與static

類模板的每個實例都有一個獨有的static對象。因此,與定義模板的成員函數類似,我們將static數據成員也定義爲模板:

template<typename T>
size_t Foo<T>::ctr = 0; //定義並初始化ctr

模板實例化

函數實例化

//compare的特殊版本,處理字符數組的指針
template<>
int compare(const char* const& p1,const char* const& p2){
	return strcmp(p1,p2);
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章