1. 程式人生 > 其它 >C++知識點62——模板實參推斷與函式模板的特化

C++知識點62——模板實參推斷與函式模板的特化

技術標籤:C++基礎c++cpp

一、函式指標與模板實參推斷

可以用函式模板初始化一個函式指標或給一個函式指標賦值

示例

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》

歡迎大家評論交流,作者水平有限,如有錯誤,歡迎指出