引出
當在C++中要實作一個通用的交換函數, 因如何實作
void Swap(int& left, int& right)
{
int temp = left;
left = right;
right = temp;
}
void Swap(double& left, double& right)
{
double temp = left;
left = right;
right = temp;
}
void Swap(char& left, char& right)
{
char temp = left;
left = right;
right = temp;
}
......
使用函數重載雖然可以實作,但是有一下幾個不好的地方:
- 重載的函數僅僅隻是類型不同,代碼的複用率比較低,隻要有新類型出現時,就需要增加對應的函數
- 代碼的可維護性比較低,一個出錯可能所有的重載均出錯
使用模闆, 相當于告訴編譯器一個模子, 就能節省很多代碼
模闆分為函數模闆和類模闆
函數模闆
示例:
template<typename T>
void Swap( T& left, T& right)
{
T temp = left;
left = right;
right = temp;
}
這樣就能實作多種基本類型的交換, 調用方法與一般的函數相同, 編譯器會自己産生相關代碼
注意:typename是用來定義模闆參數關鍵字,也可以使用class(切記:不能使用struct代替class)
類模闆
格式:
template<class T1, class T2, ..., class Tn>
class 類模闆名
{
// 類内成員定義
};
類模闆的使用參見: 類模闆的使用
注意:模闆執行個體化需要在類模闆名字後跟<>,然後将執行個體化的類型放在<> 中即可,類模闆名字不是真正的類,而執行個體化的結果才是真正的類
模闆的參數
上面能看到模闆的參數如下
template< class T>
實際上模闆的參數多種多樣, 模闆參數分為:
- 類型形參即:出現在模闆參數清單中,跟在class或者typename之類的參數類型名稱。
- 非類型形參,就是用一個常量作為類(函數)模闆的一個參數,在類(函數)模闆中可将該參數當成常量來使用。
template<class T, size_t N = 10>
class array
{
private:
T _array[N];
size_t _size;
...
}
當定義數組時, 數組的長度一般必須傳一個常量值, 不能傳變量
使用非類型形參就能夠傳數組的長度
注意:
- 浮點數、類對象以及字元串是不允許作為非類型模闆參數的。
- 非類型的模闆參數必須在編譯期就能确認結果。
模闆的特化
通常情況下,使用模闆可以實作一些與類型無關的代碼,但對于一些特殊類型的可能會得到一些錯誤的結 果,比如:
函數模闆特化
template<class T>
bool IsEqual(T& left, T& right)
{ return left == right; }
void Test()
{ char* p1 = "hello";
char* p2 = "world";
if(IsEqual(p1, p2))
cout<<p1<<endl;
else
cout<<p2<<endl;
}
此時,就需要對模闆進行特化。即:在原模闆類的基礎上,針對特殊類型所進行特殊化的實作方式。模闆特 化中分為函數模闆特化與類模闆特化
函數模闆的特化步驟:
- 必須要先有一個基礎的函數模闆
- 關鍵字template後面接一對空的尖括号<>
- 函數名後跟一對尖括号,尖括号中指定需要特化的類型
- 函數形參表: 必須要和模闆函數的基礎參數類型完全相同,如果不同編譯器可能會報一些奇怪的錯誤
template<>
bool IsEqual<char*>(char*& left, char*& right)
{ if(strcmp(left, right) > 0)
return true;
return false;
}
類模闆特化
template<class T1, class T2>
class Data
{
public:
Data() {cout<<"Data<T1, T2>" <<endl;}
private:
T1 _d1;
T2 _d2;
};
template<>
class Data<int, char>
{
public:
Data() {cout<<"Data<int, char>" <<endl;}
private:
T1 _d1;
T2 _d2;
};
void TestVector()
{
Data<int, int> d1;
Data<int, char> d2;
}
當然也可以隻特化一個參數, 叫偏特化
總結
優點:
- 模闆複用了代碼,節省資源,更快的疊代開發,C++的标準模闆庫(STL)是以而産生
- 增強了代碼的靈活性
缺點:
- 模闆會導緻代碼膨脹問題,也會導緻編譯時間變長
- 出現模闆編譯錯誤時,錯誤資訊非常淩亂,不易定位錯誤