定义:
template <typename T>
void fun(T t) {
}
特化
代码
template<typename T>
void fun1(T t) {
std::cout << "fun1(T t)" << std::endl;
}
// 通过自动推断来确定模板参数T的函数模板特化
template<>
void fun1(int t) {
std::cout << "fun1(int t)" << std::endl;
}
template<typename T>
void fun2() {
T t;
std::cout << "fun2<T>()" << std::endl;
}
// 通过显式说明模板参数T为int的函数模板特化
template<>
void fun2<int>() {
int t;
std::cout << "fun2<int>()" << std::endl;
}
int main() {
fun1(0.0);
fun1(0);
fun2<double>();
fun2<int>();
return system("pause");
}
输出
fun1(T t)
fun1(int t)
fun2<T>()
fun2<int>()
默认模板实参【C++11】
template<typename T, typename F = int>
void fun() {
}
显式指定模板实参
template <typename T>
void fun(T t) {
}
int main() {
fun<int>(0.0);
return system("pause");
}
显式实例化
// 声明函数模板实例化的作用是避免编译期多次重复实例化,可以达到加块编译速度的效果
// 下述两行代码不能出现在同一文件
template void fun(int t); // 定义,代表此处将函数模板fun()实例化为fun<int>
extern template void fun(int t); // 声明,代表承诺在别的文件有个fun<int>实例化
int main() {
fun<int>(1); // 此处实际上没有实例化的过程,会复用已经声明的实例化
return system("pause");
}
尾置返回类型的应用
// 此处不得不使用尾置返回类型,因为我们不知道beg的解引用是什么类型,而且beg知道参数列表才出现
template <typename T>
auto fun1(T beg, T end) -> decltype(*beg) {
return * beg;
}
// decltype会把(*beg)推断为引用类型,想要移除引用可以使用remove_reference<decltype(*beg)>::type
template <typename T>
auto fun2(T beg, T end) -> typename remove_reference<declval(*beg)>::type {
return * beg;
}
转发型引用
如果模板参数是T &&
的形式,则可以给它传递任何类型的实参,详情请查阅转发型引用。
重载匹配问题
template<typename T1>
void fun(T1 t1, T1 t2) {
std::cout << " 1" << std::endl;
}
template<typename T1, typename T2>
void fun(T1 t1, T2 t2) {
std::cout << "2" << std::endl;
}
void fun(int t1, double t2) {
std::cout << "3" << std::endl;
}
// 注意:特化本质上是实例化一个模板,而非重载它,不会影响函数匹配
template<>
void fun(int t1, int t2) {
std::cout << "4" << std::endl;
}
// 注意:特化本质上是实例化一个模板,而非重载它,不会影响函数匹配
template<>
void fun(int t1, double t2) {
std::cout << "5" << std::endl;
}
int main() {
// 不用经过类型转换的函数匹配都叫精确匹配,有多个精确匹配版时,根据如下规则选择:
fun(1, 1.0); // 规则一:当只有一个非模板函数精确匹配时,优先选择此函数(1、2、3中选择3)
fun(1.0, 1.0); // 规则二:规则一不满足时,优先选择更特例化的函数模板版本(1、2、3中选择1)
fun(1, 1); // 规则二:规则一不满足时,优先选择更特例化的函数模板版本(1、2、3中选择1的特化版本4)
// 规则三:上述规则都失效时,调用有二义性。
return system("pause");
}