詳談模板實例化和具體化

這裏以類模板爲例,函數模板可以類比。
其實實例化(instantiation)和具體化(specialization)這兩個東西應該分開來談,實例化的是對象,而具體化的是模板(類似於聲明)。
template <typename T1, typename T2> class Pair
{
     ...
};
Pair<string, string> ii;     //implicit instantiation    隱式實例化對象

template class Pair<int, double>;     //explicit instantiation    顯式實例化對象

template <> class Pair<const char *, int>     //explicit specialization   顯式具體化模板
{
     ...
};

template <typename T1> class Pair<typename T1, int>     //partial specialization   部分具體化模板
{
     ...
};
  1. Instantiation
一定記住一點,實例化的是對象。在面向對象的第一天就知道:對象是類的實例化!始終記住這點!
    • Implicit Instantiation
隱式實例化就像我們用類名實例化對象一樣,唯一不同的是需要在類模板後面指定該對象所需的類型參數,跟函數調用類似。
Pair<string, string> ii;     //implicit instantiation
    • Explicit Instantiation
當使用關鍵字template並指出所需類型來聲明類時,編譯器將生成類聲明的顯式實例化。聲明必須位於模板定義所在的名稱空間中。
template class Pair<string, char>;     //general Pair<string, char> class
在這種情況下,雖然沒有創建或提及類對象,編譯器也將生成類聲明(包括方法定義)。和隱式實例化一樣,也將根據通用模板來生成具體化。
想起了之前在函數模板部分中的這樣一句話:試圖在同一文件(或轉換單元)中使用同一種類型的顯式實例化和顯式具體化將出錯。意思就是說使用顯式實例化可以在模板聲明部分進行實例化,而後試圖具體化一個同種類型的模板將報錯,這樣可以避免代碼臃腫,因爲模板並不能減少代碼量,只是程序員將這部分工作交給了編譯器罷了。
另:用顯式實例化可以實現單例模式,用顯式實例化生成一個對象,然後將構造函數私有化,方法用static修飾,對象用static修飾,保證外部不能直接new出對象,必須通過方法實例化,確保了對象的唯一性。單例模式的具體實現請詳見模式設計。
  1. Specialization
先說說爲什麼要有具體化,顧名思義,就是通用模板不能處理所有的類型,所以才引入具體化。注意,具體化的都是模板!
舉個例子:假設已經爲用於表示排序後的數組定義了一個模板,假設模板使用>運算符來對值進行比較。對於數字,這管用;如果T表示一種類,則只要定義了T: :operator>( )方法,這也管用;但是如果T是有const char * 表示的字符串,這將不管用。實際上,模板倒是可以正常工作,但字符串將按地址(按照字母順序)排序。這要求類定義使用strcmp( ),而不是>來對值進行比較。在這種情況下,可以提供一個顯式模板具體化,這將採用具體類型定義的模板,而不是爲泛型定義的模板。當具體化模板和通用模板都與實例化請求匹配時,編譯器將使用具體化版本。[《C++ Primer Plus》6th P582]
引入模板的初衷就是應用泛型編程,但是引入新的必須要能夠很好的處理舊的,如果一個模板只能解決很少一部分類型,那些不能處理的類型需要重新定義一個模板,那將是一件多麼麻煩的事。所以“Specialization”很好的爲我們解決了這個問題(基本上能夠使所有類型適應該模板)。
    • Explicit Specialization
所有的具體化都是在通用模板的基礎上引申出來的,所以我們看待新事物的時候,要用類比的方式,結合舊的看待新的。
template <typename T1, typename T2> class Pair     //general template
{
     ...
};

template <> class Pair<const char *, int>     //specialization template
{
     ...
};
先注意一點,我們在使用模板實例化對象的時候其實已經使通用模板具體化爲了一個具體化模板了:
Pair<string, string> MyPair;
觀察Highlight部分,其實通用模板就是在類模板聲明的時候給了模板類型參數,使通用模板具體化爲了一個爲實現特定類型功能的模板。
再對比Underline部分,在聲明通用模板時,應該首先聲明類型參數(就像函數應該先給它參數一樣),而聲明具體化模板,可以看成是“給它的類型參數爲空”,因爲它的參數都在類名的後面(即:Highlight部分給出了)。
    • Partial Specialization
明白了顯式具體化之後再來看部分具體化就容易多了,部分具體化其實就是爲了解決顯式(全部類型參數)具體化的弊端,只需要指定部分類型參數:
template <typename T1, typename T2> class Pair     //general template
{
     ...
};

template <typename T1> class Pair<typename T1, int>     //partial specialization template
{
     ...
};
部分具體化就是在模板聲明時給出部分類型參數,如這裏就指定了第二個類型參數爲int。在需要具體的模板實例化對象時在指定第一個類型參數即可。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章