1. 程式人生 > >C++ 函數模板

C++ 函數模板

部分 blog 是什麽 str 語法 www nal 代碼 特例化

所謂模板,就是模板,但與我們所熟知的模子不同,模板用於生成不同的東西(函數或者類)。在C++中有函數模板和類模板。今天我們來探討一下函數模板。

場景:我們需要一個函數來做加法運算又或者我們需要自己實現print函數,那怎麽處理傳入參數不同(double ? int ? char ? short ? string ?)的情況呢?

你或許會脫口而出“函數重載”,但這意味著你至少要寫兩個以上的函數去支持你的參數類型和個數的變化,right?而且這種做法不支持擴展,如果有其他的需求,就必須再增加重載函數,這是比較愚蠢的,相信你也這麽認為。那麽,更好的辦法是什麽呢?函數模板。

我們來看例子??

 1 template <typename T>//先聲明模板參數 T
 2 typename T add(const T &num1, const T &num2)//定義模板函數,註意參數的類型
 3 {
 4     return num1 + num2;
 5 }
 6 
 7 int main() 
 8 {
 9     cout << add(1, 3) << endl;//模板的實例化:int add(const int &num1, const int &num2)
10     cout << add(3.0
, 9.9) << endl; //實例化:double add(const double &num1, const double &num2)
11 return 0; 12 }

這樣一來,我們就實現了一個模板,多種參數類型,從這樣說來,模板是優於函數重載的。那麽,使用他的時候,編譯器做了哪些工作呢?

1. 編譯模板本身時, 檢查語法信息;

2. 模板使用時,檢查參數類型是否匹配,數目正確與否;

3. 實例化時,進行實參推斷。

??還記得auto和decltype嗎? 這裏的實參推斷與他們類似。如上面例子中的add(1, 3),我們的實參就是int型,那麽編譯器就會將int型綁定到我們的模板類型T上,這樣一來,模板就實例化成了

int add(const int &num1, const int &num2)
{
  return num1 + num2;
}

好處是,編譯器自己進行參數類型推斷,生成函數實例,無需人為參與,也避免了,函數重載的代碼堆砌。(personal thought)一些我們使用已久的函數不就是這樣嗎?sort(),find(),reverse()...


下面我們討論一下,模板的(全)特例化與偏特例化。

【1】全特化

所謂特例化,就是將參數定死。它本質上是模板的一個特例。比如:

templete <>//標識我們在特例化模板
double
add(const double &d1, const double &d2)//參數類型具體化 { return d1 + d2; }

這裏我們就接管了部分編譯器的工作,如果同時存在模板和特例化模板, 當我們使用模板(參數與特例化一致),編譯器會優先選擇特例化模板實例(至少避免了類型推斷不是嗎?)當我們有更好更直接的函數時,要毫不猶豫地使用它。(比如:我們對傳入參數所知甚少時,就要盡量“包住“所有的可能輸入;而當我們明確知道參數類型和數量時,就應該特化它,提高效率)

【2】偏特化

偏特化是指,特化部分參數(個數特化)或者參數類型(範圍特化)。

個數特化:將幾個參數類型具體化

1 template <typename T>
2 typename T add(const T &num1, const int &num2)//特化一個參數 為int
3 {
4     return num1 + num2;
5 }

範圍特化:將參數限定在某個範圍內(指針、const ...)

1 template <typename T>
2 typename T add(const int num1, const T &num2)//將一個參數特化為 const int
3 {
4     return num1 + num2;
5 }
1 template <typename T>
2 typename T add(const int* num1, const T &num2)//將一個參數特化為 const int* 指針
3 {
4     return num1 + num2;
5 }

至於是否進行特例化,就要自己想想了。

1. 某些傳入參數沒有和其他參數一樣的特性(算術或者邏輯),我們就需要為它量身定制一個模板實例;(就好比add()例子中,要加和string怎麽辦?它可是字符數組呀。)

2. 某些參數我們是可以確定的,就可以特例化,以期更高的效率(避免類型推導和生成實例)。


類模板更為復雜,可以參考這裏

C++ 函數模板