1.5重载模板函数
对于非模板函数重载不想解析太多,那是C语言范畴已有的编程技术,若你本身没概念的话,请返回上一篇文章前文提要。
首先一个重要的概念,模板函数的签名,它就代表了一个特定函数名称的函数重载集的抽象接口,例如
下面的示例1是示例2的进一步抽象
示例1
template<typename T1,typename T2>
auto max(T1 ,T2);
示例2
template<typename T>
auto max(T,T);
再看看下面的示例
模板函数的重载规则
如本示例所示
- 非模板函数可以与具有相同名称并可以用相同类型实例化的函数模板共存。
- 在所有其他因素相同的情况下,重载解析过程优先选择已匹配的非模板函数而不是从模板生成的函数。 不论你以后什么顺序调用max(10,11),编译器始终匹配已存在的int max(int a, int b)
- 若在模板函数集合中,可以找到匹配度更"具体"的模板函数,那么编译器优先选择更具体的模板函数而非更抽象的模板.
int max(int a,int b){
std::cout<<"int max(int,int)"<<std::endl;
return a>b?a:b;
}
template<typename T>
auto max(T a,T b){
std::cout<<"auto max(T a,T b);"<<std::endl;
return a>b?a:b;
}
template<typename T1,typename T2>
auto max(T1 a,T2 b){
std::cout<<"auto max(T1 a,T2 b);"<<std::endl;
return a>b?a:b;
}
int main(void){
auto r1=::max(4,7.2);
auto r2=::max(22.1,8.3);
auto r3=::max(7.2,4);
auto r4=::max(10,11);
auto r5=::max("Hello IT-dog","Hi,Cally!");
std::cout<<"r1:"<<r1<<std::endl;
std::cout<<"r2:"<<r2<<std::endl;
std::cout<<"r3:"<<r3<<std::endl;
std::cout<<"r4:"<<r4<<std::endl;
std::cout<<"r5:"<<r5<<std::endl;
}
下面的函数输出,更好地说明了一切。
2019-12-28 10-46-04屏幕截图.png
其实上面的示例,只是为了演示模板函数的重载规则,实际写代码过程中应尽量保持模板函数的简洁,我们只需抽象的模板函数即可。
到目前为止,我们用过的示例基本上都是通过按值传递,而不是按引用传递,通常,对于廉价的简单类型(例如基本类型或std :: string_view)以外的类型,建议通过引用传递,因为不会创建不必要的副本。
但是,出于两个原因,通常通过价值传递语法很简单。
- 编译器优化效果更好。
- 移动语义通常会使副本便宜。
- 有时根本没有副本或移动。
另外,对于模板,特定方面也起作用:
- 模板可能同时用于简单类型和复杂类型,因此为复杂类型选择方法可能适得其反。
作为调用者函数,您仍然经常可以使用std::ref()和std::cref()来决定通过引用传递参数(请参阅原书的第112页的7.3节)。
网友评论