C++11函式模板的預設模板引數
1.函式模板預設模板引數簡介
函式模板與類模板在C++98一起被引入,因種種原因,類模板可以擁有預設模板引數,而函式模板不可以。從C++11開始,這個限制被解除了,即函式模板同樣可以擁有預設模板引數。預設模板引數的用法與函式的預設引數類似,考察如下示例:
#include <iostream> using namespace std; //函式預設引數 void testFunc(int param=4) { cout<<"param="<<param<<endl; } //類模板預設模板引數 template<typename T=int> class TestClass { public: static void _printTypeName() { cout<<"T="<<typeid().name()<<endl; } }; //函式模板的預設模板引數,C++11開始支援 template<typename T=int> void testTemplateFunc(T param) { cout<<"TemplateFunc's param="<<param<<endl; } int main() { testFunc(); TestClass<>::_printTypeName(); testTemplateFunc<>(4); }
編譯執行輸出:
param=4
T=int
TemplateFunc's param=4
在對函式模板testTemplateFunc進行顯示呼叫時,並沒有指明模板引數,而是使用預設的模板引數int,可以正確編譯並執行輸出預期結果。
2.函式模板預設模板引數的特點
函式模板預設模板引數的用法雖然與類模板預設模板引數和函式預設引數的用法類似,但是有一個顯著的特點,即當函式模板擁有多個預設模板引數時,其出現的順序可以任意,不需要連續出現在模板引數的最後面。考察如下示例:
void testFunc(int param1=4,int param2){} //編譯失敗 template<typename T1=int,typename T2> class TestClass{}; //編譯失敗 template<typename T1=int,typename T2> void testTemplateFunc(T1 param,T2 param2){} //編譯成功
從上面的程式碼可以看出,不按照從右往左指定函式的預設引數和類模板的預設模板引數均導致編譯錯誤,而在C++11中,函式模板的預設模板引數出現的位置則比較靈活,可以出現在任意位置。
2.3函式模板的引數推導規則
函式模板的引數推導規則是如果能夠從函式實參中推匯出型別的話,則函式模板的預設模板引數則不會被使用,反之,預設模板引數則可能被使用。考察如下示例:
template<typename T,typename U=double> void testTemplateFunc(T t=0,U u=0) { cout<<"t="<<t<<" u="<<u<<endl; } int main() { testTemplateFunc(4,'a'); //呼叫testTemplateFunc<int,char>(4,'a') testTemplateFunc(4); //呼叫testTemplateFunc<int,double>(4,0) //testTemplateFunc(); //編譯失敗 testTemplateFunc<int>(); //呼叫testTemplateFunc<int,double>(0,0) testTemplateFunc<int,char>(); //呼叫testTemplateFunc<int,char>(0,0) }
程式編譯執行輸出:
t=4 u=a
t=4 u=0
t=0 u=0
t=0 u=
函式模板的模板引數是由函式的實參推導而來,因此函式呼叫testTemplateFunc(4)
將根據函式模板例項化出模板函式後的呼叫是testTemplateFunc<int,double>(4,0)
,其中第二個模板引數U使用了預設的模板型別引數double,實參則使用了預設引數0。同理,函式呼叫testTemplateFunc<int>()
最終的呼叫是testTemplateFunc<int,double>(0,0)
。而函式呼叫testTemplateFunc()
則因為無法推匯出第一個模板引數T,導致編譯出錯。
從上面的例子也可以看出,因為函式模板的模板引數是由函式的實參推導而來,所以預設模板引數通常需要跟預設函式引數一起使用,不然預設模板引數的存在將沒有意義。
參考文獻
[1]深入理解C++11[M].2.11模板函式的預設模板引數