c/c++ 模板函数的重载
模板函数的重载
普通函数可以重载,模板函数也可以重载,但规则复杂
有下面2个函数,名字相同,返回值相同就,参数不同,符合重载。
template<typename T>
std::string moban(const T& t){}
template<typename T>
std::string moban(T* p){}
调用1
std::string s("hi");
std::cout << moban(s) << std::endl;
结果1:调用的是(const T& t),这个可以简单理解,因为参数不是指针类型,所以不适用于(T* p)。
调用2
std::string s("hi");
std::cout << moban(&s) << std::endl;
结果2:调用的是(T* p)。这个就复杂了,因为2个模板都符合,但是调用哪个呢。
- moban(const string*&) T被绑定到string*。
- moban(string*) T被绑定到string。
因为(const T& t)的实例需要进行普通指针到const指针的转换,(T* p)不需要转换,所以是更精准的匹配。
所以推导出规则1:更精准的匹配会被优先采用。
调用3
std::string s("hi");
const std::string* sp = &s;
std::cout << moban(sp) << std::endl;
结果3:调用的是(T* p)。这个就更复杂了,因为2个模板都符合,而且都是同样精准的匹配,但是调用哪个呢。
- moban(const string*&) T被绑定到string*。
- moban(string*) T被绑定到const string。
在此情况下,因为是同样精准的匹配,所以无法区分调用哪个。但是根据重载函数模板的特殊规则,调用了(T* p)。
原因是,(const T& t)本质上可以用于任何类型,包括指针类型,比(T* p)更通用,后者只能用于指针类型。
所以推导出规则2:同样精准的话,更特殊的会被优先采用。
如果非模板函数和模板函数同时存在,构成重载,会调用哪个?
有下面3个函数,名字相同,返回值相同就,参数不同,符合重载。
template<typename T>
std::string moban(const T& t){}
template<typename T>
std::string moban(T* p){}
std::string moban(const std::string& s){}
调用4
std::string s("hi");
std::cout << moban(s) << std::endl;
结果4:调用的是非模板的函数。
- (const T& t) T被绑定到string,也是可以被调用的。
但是,非模板优先模板。
所以推导出规则3:非模板和模板同时都适用的时候,非模板的会被优先采用。
调用5
std::string s("hi");
std::cout << moban(s) << std::endl;
结果5:调用的是(T* p),而没有调用非模板函数。
所以看出来,规则3有个特例,就是,如果模板的匹配比非模板的匹配更精准的时候,模板会被优先采用。
- moban(const T& t) T被绑定到char[2]。
- moban(T*) T被绑定到const char。
- moban(const std::string& s) 要求从const char*到string的类型转换。
理由:非模板也是可行的,但是需要进行一次用户定义的类型转换,因此她没有模板的匹配更精准。但是2个模板都可以被调用,但是(T*)更特例化,所以最好调用的是(T*)
所以推导出规则4:非模板和模板同时都适用的时候,非模板如果需要一次用户定义的类型转换,而模板不需要的话,模板会被优先采用。
非模板函数和模板函数的声明位置,导致结果的不同。
有下面4个函数,名字相同,返回值相同就,参数不同,符合重载。
template<typename T>
std::string moban(const T& t){}
template<typename T>
std::string moban(T* p){}
std::string moban(const char* p){
return debug_rep(std::string(p));
}
std::string moban(const std::string& s){}
调用5
std::cout << moban("hello") << std::endl;
结果5:首先调用的是(const char* p),这是没有疑问的,它是最匹配的,问题是它里面的return debug_rep(std::string(p));调用的是哪个呢?调用的是:(const T& t)。
分析:由于非模板的(const std::string& s)的定义在,(const char* p)的后面,所以return debug_rep(std::string(p));只能看到它前面的2个模板函数,所以匹配了(const T& t)。如果把(const std::string& s)的定义放在,(const char* p)的前面,return debug_rep(std::string(p));调用的就是非模板的(const std::string& s)。
c/c++ 学习互助QQ群:877684253

本人微信:xiaoshitou5854
c/c++ 模板函数的重载的更多相关文章
- 聊聊C++模板函数与非模板函数的重载
前言 函数重载在C++中是一个很重要的特性.之所以有了它才有了操作符重载.iostream.函数子.函数适配器.智能指针等非常有用的东西. 平常在实际的应用中多半要么是模板函数与模板函数重载,或者是非 ...
- [C++] 用Xcode来写C++程序[5] 函数的重载与模板
用Xcode来写C++程序[5] 函数的重载与模板 此节包括函数重载,隐式函数重载,函数模板,带参数函数模板 函数的重载 #include <iostream> using namespa ...
- [c++][语言语法]函数模板和模板函数 及参数类型的运行时判断
参考:http://blog.csdn.net/beyondhaven/article/details/4204345 参考:http://blog.csdn.net/joeblackzqq/arti ...
- C++:函数模板与模板函数
6.1 模板的概念 C++允许用同一个函数定义函数,这些函数的参数个数和参数类型不同.例如求最大值的max函数, int max(int x,int y) { return (x>y ...
- C++模板专门化与重载
最近在复习C++有关知识,又重新看<<Effective C++>>,收获颇丰.原来以前看这边书,好多地方都是浅尝辄止.<<Effective C++>> ...
- [转]C++函数模板与模板函数
1.函数模板的声明和模板函数的生成 1.1函数模板的声明 函数模板可以用来创建一个通用的函数,以支持多种不同的形参,避免重载函数的函数体重复设计.它的最大特点是把函数使用的数据类型作为参数. ...
- C++普通函数与模板函数以及特化函数重载的优先级问题
在面对C++模板的时候,需要十分注意,因为模板的复杂性有很多情况,所以最好学习模板的方法我个人认为就是用到就去学,用不到就尽量别去看各种奇门怪技,因为你就算看了,好不容易搞懂模板的实现内部了,包括元编 ...
- c++模板函数实例化的偏序机制
一:废话 今天在stackoverflow上看到一个关于c++模板specialization的问题: http://stackoverflow.com/questions/18283851/temp ...
- C++ template学习一(函数模板和模板函数)
函数模板和模板函数(1)函数模板函数模板可以用来创建一个通用的函数,以支持多种不同的形参,避免重载函数的函数体重复设计.它的最大特点是把函数使用的数据类型作为参数.函数模板的声明形式为:templat ...
随机推荐
- 华为模拟器eNSP安装(最新)网络工程师必备!
电脑杂七杂八的东西太多了,于是今天把电脑重装系统了,正好重新安装一下华为模拟器eNSP,这个教程应该是最新的,因为eNSP版本更新以及华为官网页面的变化,有的小伙伴安装eNSP都下载不到安装包,接下来 ...
- Android startActivity原理分析(基于Android 8.1 AOSP)
应用进程内 如何使用Intent做Activity的跳转 Intnet intent = new Intent(MainActivity.this,TestActivity.class); start ...
- Linux系统的启动过程
Linux 系统启动过程 Linux系统的启动过程可以分为5个阶段: BIOS自检 内核的引导. 运行init. 系统初始化. 用户登录系统. BIOS自检: BIOS是英文"Basic I ...
- Storm入门(十四)Trident API Overview
The core data model in Trident is the "Stream", processed as a series of batches. A stream ...
- Storm入门(七)可靠性机制代码示例
一.关联代码 使用maven,代码如下. pom.xml 参考 http://www.cnblogs.com/hd3013779515/p/6970551.html MessageTopology. ...
- ReactiveSwift源码解析(六) SignalProtocol的take(first)与collect()延展实现
上篇博客我们聊了observe().map().filter()延展函数的具体实现方式以及使用方式.我们在之前的博客中已经聊过,Signal的主要功能是位于SignalProtocol的协议延展中的, ...
- AJAX跨域请求详解
最近开始学习ajax,学习ajax必须得掌握的就是跨域请求,实际上在不同源的地址上发送请求就是跨域请求 域名地址的组成: http:// www . google : 8080 / script/jq ...
- 2. VIM 系列 - 初探vim配置文件
目录 配置文件 .vimrc 基本配置 tab 键设置 热键配置 配置文件 刚安装vim默认配置,功能是很简单的,vim的功能很多是需要配置开启的. .vimrc 使用vim打开配置文件~/.vimr ...
- ubuntu-18.04 设置开机启动脚本-亲测有效
ubuntu-18.04不能像ubuntu14一样通过编辑rc.local来设置开机启动脚本,通过下列简单设置后,可以使rc.local重新发挥作用. 2.将下列内容复制进rc-local.servi ...
- 死磕 java集合之ConcurrentSkipListMap源码分析——发现个bug
前情提要 点击链接查看"跳表"详细介绍. 拜托,面试别再问我跳表了! 简介 跳表是一个随机化的数据结构,实质就是一种可以进行二分查找的有序链表. 跳表在原有的有序链表上面增加了多级 ...