C++知識點62——模板實參推斷與函式模板的特化
阿新 • • 發佈:2020-12-28
一、函式指標與模板實參推斷
可以用函式模板初始化一個函式指標或給一個函式指標賦值
示例
template <typename T>
int comp(const T &a, const T &b)
{
return 0;
}
int main(int argc, char const *argv[])
{
int (*pf)(const int &, const int &)=comp;
}
上述程式碼通過函式指標的形參型別指定了函式模板的模板引數T的型別為int
示例2
void func(int (*pf)(const int &, const int &)){} void func(int (*pf)(const string &, const string &)){} int main(int argc, char const *argv[]) { func(comp<int>); }
func是個過載函式,如果把函式模板傳入func後,會引起二義性錯誤,因為此時,編譯器無法確定模板引數到底是int還是string,所以需要顯示指定模板引數
二、模板引數與引用
如果函式模板的模板引數作為引用型別的形參,那麼,當傳入一個數組時,形參的型別是陣列的引用
示例
template <typename T> const T & max(const T &a, const T &b) { cout<<typeid(a).name()<<endl; cout<<typeid(b).name()<<endl; return a>b?a:b; } int main(int argc, char const *argv[]) { int a[]={1,2,3,4}; int b[]={2,3,4,5}; ::max(a, b); ::max("1234", "2345"); return 0; }
這裡T被分別推斷為int陣列和char陣列,因為T同時作用於兩個形參,且例項化後,形參的型別是陣列的引用,所以陣列的大小必須相同
如果函式模板的模板引數作為值型別的形參,那麼,當傳入一個數組時,形參的型別會退化成指標
template <typename T> const T & max(T a, T b) { cout<<typeid(a).name()<<endl; cout<<typeid(b).name()<<endl; return a>b?a:b; } int main(int argc, char const *argv[]) { int a[]={1,2,3,4}; int b[]={2,3,4,5}; ::max(a, b); ::max("1234", "2345"); return 0; }
此時,T的型別只是個指標,所以,並不要求陣列的大小
上述兩點其實並沒有什麼特別,和以前一樣,當我們把一個數組傳遞給一個型別是陣列的引用的形參時,陣列不會退化成指標,當我們把一個數組傳遞給一個型別是陣列的形參時,陣列形參會變成一個指標
三、const與模板實參推斷
如果函式模板的模板引數作為普通形參,那麼當傳入const型別的實參
template <typename T>
void constest(T a){cout<<typeid(a).name()<<endl;}
int main(int argc, char const *argv[])
{
const int a=10;
constest(a);
}
和之前一樣,對於值傳遞,頂層const會被忽略
雖然傳入了const int,但是此時T被指定為int
四、函式模板的特化
類模板可以被特化,函式模板也可以被特化,規則也是在template後面加個<>
示例
template <typename T>
int comp(const T &a, const T &b)
{
cout<<typeid(T).name()<<endl;
return 0;
}
template <>
int comp(const string &a, const string &b)
{
return 0;
}
和類模板一樣,函式模板特化本質依舊是例項化的一種,並不是過載
和類模板不同的是,函式模板不能區域性特化
參考
《C++ Template》
《C++ Primer》
歡迎大家評論交流,作者水平有限,如有錯誤,歡迎指出