模板本身不是可編譯的**,而是用來指導編譯器生成可編譯**的文字。
1 函式模板引數
函式模板引數可以根據模板實參自動推導,也就是說可以從實參自動推導的模板引數可以省略書寫,但是要注意以下幾個規則:
1) 編譯器只根據函式呼叫時給出的實參列表推導模板引數值,與函式引數無關的模板引數無法推導
2) 與函式返回值相關的模板引數其值也無法推導
3) 所有可推導模板引數必須是連續位於模板引數列表尾部,中間不能有不可推導的模板引數
乙個例子如下:
#include
template
t2 func(t1 v1, t3 v3, t4 v4);//模板引數中可函式函式關聯的是t1 t3 t4
int main()
template
t2 func(t1 v1, t3 v3, t4 v4) 說明:模板引數中t0滿足1)故不能通過函式引數推導出,t2滿足2),因此t0和t2在模板例項化時都不能省略,由於t1在t2之前故也不能省略(c++不支援跳過t1的賦值)。故上面三種例項化的都是例項化而t3和t4是由函式的實參自動推導而來的。
c++11允許模板函式可以和模板類一樣具有模板引數預設值,故可以將t0和t2宣告乙個預設值,如下:
template
t2 func(t1 v1,t3 v3,t4 v4);
fun(1,2,3);//通過給t0和t2指定了預設的模板引數值後,此處所有的模板引數都可以省略書寫了
fun(1,'a','b');模板函式中的靜態變數是否會像普通函式中的靜態變數只有乙份?通過輸出可以看出,sv0和sv2值在前兩次func呼叫時由0變到-1,這是因為前兩次呼叫例項化模板都是func有乙份共同的例項化函式體。當有多個呼叫使用相同的模板引數值時,編譯器只為此模板引數值生成同一函式而將不同呼叫都鏈結在同一函式上,只要有任意模板引數值不同編譯器就會生成不同的函式體以供鏈結。總之,編譯器為同一組模板引數值只生成唯一函式體。
假設上面檔案編譯g++ test.cpp 那麼檢視a.out檔案:nm -c a.out |grep func |grep w 輸出如下,只有三個模板例項化函式體,可見前兩次func共享func:
0000000000400b94 w int func(int, double, double)
0000000000400acf w int func(int, int, int)
0000000000400c73 w double func(double, double, double)
2 模板檔案組織
通常的c++工程組織都是將函式宣告之類的放在.hpp中,函式實現放在.cpp中。但是對於模板來說這樣組織會導致連線錯誤,因為.hpp中只是模板的宣告,.cpp中是模板的實現並沒有任何模板例項化的語句故不會生成任何模板例項化**,那麼在其它.cpp中例項化模板時導致無法找到模板**導致鏈結錯誤。
當乙個工程中連線多個檔案時可能出現相同的模板例項化**,如下:
//***********************************===
//檔名caller1.cpp
#include
template
void func(t const &v)
void caller1()
//***********************************===
//檔名caller2.cpp
#include
template
void func(t const &v)
void caller2()
//***********************************===
//檔名main.cpp
void caller1();
void caller2();
int main()
程式輸出:
func1: 1
func1: 0.1
func1: 2
func2: 0.2
可見上面的caller1()和caller2()都例項化了同乙個func,且都是使用caller1的func。因為編譯器會根據函式名、模板實參列表、引數列表將棄用等價的模板函式(儘管它們的函式體不一樣),而棄用哪個檔案的函式是隨機的,可能與檔案的連線順序有關。
這樣就導致了乙個問題,不同函式體實現的函式被棄用了,可能導致一些截然不同的結果,怎樣避免呢?盡量採用不同的函式名,採用命名空間隔離。但是不要強制採用using namespace這樣暴力的方式將命名空間所有的元素包含進另乙個命名空間,這樣可能會造成如上的函式重複例項。採用using 引用函式。
這裡提下using在c++11中的兩個用途:
1) 引用,如下:
class base;
class derived:public base;
2) 自定義功能,完全替代了typedef,如下:
using size_t=decltype(sizeof(0));//通過decltype自動推導功能實現了size_t跨平台的移植
3 外部模板
c++11已經棄用了export語義,即在不同檔案中在template前加上export就可以例項化模板。c++11的extern作為外部模板語義,如下:
//檔案test.hpp
template
void fun();
//檔案test1.cpp
template void fun(int);//顯示例項化出了乙個fun的版本
//檔案test2.cpp
extern template void fun(int);//外部模板的宣告通過上面的宣告方式,test1.cpp和test2.cpp編譯連線後fun都是共享test1.cpp的模板例項化**。
函式模板例項
函式模板例項 這是值得考慮一下如何模板函式的實現在c 因為未來的教訓將關閉一些這些概念。原來,c 不編譯模板函式直接。相反,在編譯的時候,當編譯器呼叫乙個函式模板,它複製的模板功能,並與實際型別代替模板型別引數!與實際型別的函式被呼叫函式模板例項。讓我們來看看這樣乙個例子看看。首先,我們有乙個模板函...
C 函式模板與類模板例項解析
c 函式模板與類模板例項解析 本文針對c 函式模板與類模板進行了較為詳盡的例項解析,有助於幫助讀者加深對c 函式模板與類模板的理解。具體內容如下 泛型程式設計 generic programming 是一種程式設計正規化,通過將型別引數化來實現在同乙份 上操作多種資料型別,泛型是一般化並可重複使用的...
C 函式模板與類模板例項解析
泛型程式設計 generic programming 是一種程式設計正規化fmlqt,通過將型別引數化來實現在同乙份 上操作多種資料型別,泛型是一般化並可重複使用的意思。泛型程式設計最初誕生於c 中,目的是為了實現c 的stl 標準模板庫 模板 template 是泛型程式設計的基礎,乙個模板就是乙...