泛型編程就是以獨立於任何特定類型的方式編寫代碼,而模板是泛型編程的基礎。
(1)定義函數模板(function template)
函數模板是一個獨立於類型的函數,可以產生函數的特定類型版本。
// implement strcmp-like generic compare function
template <typename T>
int compare(const T &v1, const T &v2)
{
if (v1 < v2) return -1;
if (v2 < v1) return 1;
return 0;
}
模板定義以關鍵字template開始,後接尖括號括住的模板形參表。
模板形參可以是表示類型的類型形參(type parameter),也可以是表示常量表達式的非類型形參(nontype parameter)。上面程序中的T是類型形參。
// compiler instantiates int compare(const int&, const int&)
cout << compare(1, 0) << endl;
// compiler instantiates int compare(const string&, const string&)
string s1 = “hi”, s2 = “world”;
cout << compare(s1, s2) << endl;
使用函數模板時,編譯器會將模板實參綁定到模板形參。編譯器將確定用什麼類型代替每個類型形參,用什麼值代替每個非類型形參,然後產生並編譯(稱爲實例化)該版本的函數。
上面的例子中,編譯器用int代替T創建第一個版本,用string代替T創建第二個版本。
函數模板也可以聲明爲inline。
// inline specifier follows template parameter list
template <typename T> inline T min(const T&, const T&);
(2)定義類模板(class template)
在定義的類模板中,使用模板形參作爲類型或值的佔位符,在使用類時再提供具體的類型或值。
template <typename Type>
class Queue
{
public:
Queue();
Type & front();
const Type & front() const;
void push(const Type &);
void pop();
bool empty() const;
private:
// …
};
與調用函數模板不同,使用類模板時,必須爲模板形參顯示指定實參。Queue<int> qi; // Queue that holds ints
Queue<string> qs; // Queue that holds strings
(3)模板類型形參
類型形參由關鍵字class或typename後接說明符構成。在函數模板形參表中,二者含義相同。typename其實比class更直觀,更清楚的指明後面的名字是一個類型名(包括內置類型),而class很容易讓人聯想到類聲明或類定義。
此外,在使用嵌套依賴類型(nested depended name)時,必須用到typename關鍵字。
在類的內部可以定義類型成員。如果要在函數模板內部使用這樣的類型,必須顯示告訴編譯器這個名字是一個類型,否則編譯器無法得知它是一個類型還是一個值。默認情況下,編譯器假定這樣的名字指定(靜態)數據成員,而不是類型。所以下面這段程序,如果去掉typename關鍵字,將會出現編譯錯誤。
template <typename Parm, typename U>
Parm fcn(Parm *array, U value)
{
typename Parm::size_type * p;
}
(4)非類型模板形參
模板形參也可以是非類型形參,在使用時非類型形參由常量表達式代替。
// initialize elements of an array to zero
template <typename T, size_t N>
void array_init(T (&parm)[N])
{
for (size_t i = 0; i != N; ++i)
parm[i] = 0;
}
…
int x[42];
double y[10];
array_init(x); // instantiates array_init(int (&)[42])
array_init(y); // instantiates array_init(double (&)[10])
(5)編寫泛型程序
模板代碼需要對使用的類型做一些假設,比如上面的compare()要求類型T重載了“<”操作符。所以函數模板內部完成的操作就限制了可用於實例化該函數的類型。
編寫模板代碼時,對實參類型的要求應儘可能少。比如compare()函數僅使用了“<”操作符,而沒有使用“>”操作符。
【學習資料】 《c++ primer》