一、函数指针与模板实参推断
可以用函数模板初始化一个函数指针或给一个函数指针赋值
示例
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》
欢迎大家评论交流,作者水平有限,如有错误,欢迎指出