c++模板

原文:http://blog.csdn.net/rendaduiyan/article/details/378234

C++模板

模板首先是一種設計理念,其次纔是一種C++語法。只有先理解了模板,才能更好的使用C++中的模板特性。
模板的概念

爲了能理解模板,可以先了解一下模具:爲了生產一種產品,例如茶具,需要先設計其模具,有了模具後,能夠輕易地成批量的生產出成千上萬的產品。模具的特點是一次設計,反覆使用。模具具有了模板的重用性特點;但卻少了可擴展的特點:其產品是一成不變的,如果某人想把茶具的外形少作改動,則此模具就作廢了。

爲了兼有重用性和可擴展的優點,需要將不變的部分和變化的部分分開,把不變的部分做成模具骨架,把變化的部分作爲模具的子部分存在。例如對汽車,可以認爲車架、油路系統、電路系統,輪胎構成了一輛汽車的骨架,至於是什麼樣的車架、油路系統、電路系統在骨架中不體現出來,只是把這些部分的接口數據全定義出來了,只要滿足這些定義的子部分部件,都能往骨架中放。可以這麼簡單的理解:骨架都有一些佔位符組成,佔位符組成有其定義,符合這些佔位符定義的符號都能放入骨架中,以實現不同的功能。

現在把模板的定義上升到理論高度:“定義一個操作中算法的骨架,而將一些步驟延遲到子類中”[1];“各子類的公共行爲被提前提取出並集中到一個公共父類中避免代碼重複”[1]。

需要說明的是,這裏所說的子類不是隻對模板類的派生,而是指模板類的參數化類別。模板已是設計模式[1]之一;模板通常有兩個角色:

抽象類:定義抽象的原語操作(可以簡單的定義了一些接口),其具體實現放到子類中;

具體類:實現原語操作以完成算法中與特定子類相關的步驟,即實現抽象類定義的接口。
模板的語法

在C++中,分兩個層次使用模板:模板函數,模板類。
模板函數

一般在頭文件中定義模板函數,如

#ifndef _POS_H_

#define _POS_H_

template<class T>

T* pos(cosnt T& value, T* begin,T* end)

{

for(; begin < end; begin ++)

{

if(*begin == value)

{

return begin;

}





}

}

#endif

要使用模板函數,需要對模板函數進行實例化,如下的例子使模板被實例化兩次:

#include “pos.h”

#include <string>

using namespace std;

int main(int argc, char ** argv)

{

int int_array[30];

string string_array[30];



int iptr = pos(-1, &int_array[0], &int_array[30]);

string* sptr = pos(string(“sam”, &string_array[0], &string_array[30]);

return 0;

}
模板類

模板類的定義與模板函數類似,可以把模板類的成員函數與類定義一起放到頭文件中,如:

#ifndef _VECTOR_H_

#define _VECTOR_H_

template <class T>

class Vector

{



};




template <class T>

vector<T>::vector():tptf(new T[10], length(10){}

//對於在cpp文件中的實現方式同樣需要如此定義



#endif

模板類的使用也類似,如:

#include <Vector.h>

int main(int argc, char** argv)

{

Vector<int> int_vec;

Vector<string> str_vec;



return 0;

}
模板特化

模板特化分兩種:完全特化和偏特化;完全特化是模板的一種窮舉方式,是指參數的完全固定化,即所以參數都有一個具體的類型,如:

template<bool> struct CompileTimeChecker{};

template<> struct CompileTimeChecker<true>

{

CompileTimeChecker(…){};

};

後者即是模板類CompileTimeChecker類的特化版本,因爲它把bool類型的參數固定爲true。

而偏特化與完全特化是想對的,只有一個參數的模板類,無法偏特化;這是因爲偏特化只能固定模板類的部分參數,而非全部(如果是全部,就變成了完全特化了)。如:

template<class T, class U>

class Conversion

{



};

template <class T>

class Conversion<T, T>

{

public:

enum{exists = 1, sameType = 1};

}

後者實現了對模板類Conversion的偏特化版本,即兩個參數T和U類型相同的情況。Visual C++ 6不支持對模板類的偏特化。
type traits

Type Traits是範型編程中用於編譯是類型判斷的一項技術,其主要思想是利用函數特化(特別是完全特化),來爲模板類定義一些輔助常量和函數,以便於在編譯時進行類型判斷。例如,想對指針和非指針類型做區分,以編譯進行不同的處理,就可以使用Type Traits技術。

Template <typename T>

Class TypeTraits

{

private:

template<class U>struct PointerTraits

{

enum{result = false;};

typedef NullType PointeeType;

};

template<class U> struct PointerTraits<U*>

{

enum{result = true ;};

typedef U PointeeType;

};

public:

enum{isPointer = PointerTraits::result};

typedef PointerTraits<T>::PointeeType PointeeType;

};

上面的例子,把非指針類型定義其枚舉變量result爲false,這是一種範型結果;而對指針類型,利用特化版本,另外定義其結果爲true;爲了對外有一致的接口,對非指針類型用了一個空指針佔位NullType,並都定義了類型PointeeType。在模板實例化時,會根據不同的參數類型調用不同的版本。

TypeTraits的主要用途主要是用於代碼優化,因爲如果知道類型後,就能利用特殊方法進行處理。如對char的複製,可以直接使用memcpy,這是C++中最快的複製方式;對有雙CPU的機器,可以使用直接比特流複製等。
模板與編譯器

編譯器怎麼樣實現模板的呢?

² 編譯:在編譯如上的例子程序時,編譯器從pos.h中讀到了模板定義,並根據在main中實例化的情況,編譯器會自動生成兩個版本的pos函數:pos(const int&, int*, int*)和pos(string&, string*, string*)。

² Borland C++,VC, Sun Workshop, HP aCC和G++:編譯器在main.o或者main.obj中擴展pos函數兩次。

² EDG-based C++或者G++帶-frepo參數:編譯器直到鏈接時才展開pos函數,但編譯時會在本地數據庫(EDG的main.ii-實例化信息文件,G++的main.pro-倉庫文件)中生產記錄參數化信息。
模板的副作用

模板是好東西,但也有其副作用,世界就是這麼公平:

對於鏈接時實例化:鏈接更加耗時;在實例化時會遞歸很多此來得到所以成員函數的全部版本。

對眼編譯時實例化:目標代碼變大;很難有選擇地實例化模板類成員函數地幾個版本,即實現全部版本。

會帶來不必要的代碼編寫,如模板類中實現了操作符<<,並在其中引用此操作符,在實例化模板類時,編譯器會要求你的類實現此操作符,即是你的應用程序根本不會使用此操作符,否則編譯失敗。
結束語

模板技術常用於類庫編程和範型編程,因爲其主要思想是提煉算法骨幹,延遲細節處理;使用好了模板將使類庫代碼短小精悍;模板讀設計思路是一種抽象和複用,能夠提高設計的效率。

發佈了2 篇原創文章 · 獲贊 4 · 訪問量 4萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章