C++ 函数模板的返回类型如何确定?
函数模板
#include <iostream>
// 多个参数的函数木板
template<typename T1, typename T2>
T2 max(T1 a, T2 b) {
using namespace std;
cout << "调用的自定义模板函数...... " << endl;
return b < a ? a : b;
}
// 显式指定模板参数的类型
template<typename T>
T max1(T a, T b) {
using namespace std;
cout << "显式指定模板参数...... " << endl;
return b < a ? a : b;
}
int main() {
using namespace std;
double a = ::max(2, 3.2);
cout << "max(2, 3.2) = " << a << endl;
double b = ::max1<double>(2, 4);
cout << "max1<double>(2, 4) = " << b << endl;
return 0;
}
函数模板有两种不同类型的参数:
模板参数:在尖括号中声明的
template<typename T>
调用参数:函数模板名称的括号中声明的
T max(T a, T b)
如果使用了多个模板类型参数的话,返回值有时候是个问题,对此有三种方法:
- 为返回值单独引入一个模板类型参数
- 让编译器找到返回类型
- 声明一个其他类型的共同类型
返回值的模板参数
函数模板可以自动检测模板参数类型,因此我们可以不同显式指定,当然显式指定也可以的。
比如:
#include <iostream>
// 显式指定模板参数的类型
template<typename T>
T max1(T a, T b) {
using namespace std;
cout << "显式指定模板参数...... " << endl;
return b < a ? a : b;
}
int main() {
using namespace std;
double b = ::max1<double>(2, 4);
cout << "max1<double>(2, 4) = " << b << endl;
return 0;
}
在进行 ::max1<double>(2, 4); 调用的时候,就是显式指定了模板参数。
现在来一个为返回值引入第三个模板参数:RT max(T1 a, T2 b);
#include <iostream>
// 多个参数的函数木板
template<typename T1, typename T2, typename RT>
RT max(T1 a, T2 b) {
using namespace std;
cout << "调用的自定义模板函数...... " << endl;
return b < a ? a : b;
}
int main() {
using namespace std;
double a = ::max(2, 3.2);
cout << "max(2, 3.2) = " << a << endl;
return 0;
}
然后编译的时候就报错了:

报错信息提示:参数 deduction(推理)失败了
这里引出了自动推理的规则:
如果模板参数和调用参数的类型没有什么关系,那么在调用的时候 参数模板的所有类型是不能完全确定的,你必须显式指定模板参数。
因此显式指定以下就可以了:
#include <iostream>
// 多个参数的函数木板
template<typename T1, typename T2, typename RT>
RT max(T1 a, T2 b) {
using namespace std;
cout << "调用的自定义模板函数...... " << endl;
return b < a ? a : b;
}
int main() {
using namespace std;
// 模板参数和调用参数不能完全匹配的时候需要显式指定
double a = ::max<int, double, double>(2, 3.2);
cout << "max(2, 3.2) = " << a << endl;
return 0;
}
编译通过,运行成功。
但是指定所有的模板类型又有点啰嗦,这里又来了一条规则:
你必须显式指定直到最后一个不能确定的所有模板类型。
比如上面例子中,RT 的类型是不能通过参数类型推理来确定的,所以导致 T1 和 T2 的类型都要显式指定。
因此这里来了一个骚操作,就是把不能指定的模板类型都放在模板参数列表的最前面,那么后面可以确定的模板参数就可以不用显式指定了。
#include <iostream>
// 多个参数的函数木板
template<typename RT, typename T1, typename T2>
RT max(T1 a, T2 b) {
using namespace std;
cout << "调用的自定义模板函数...... " << endl;
return b < a ? a : b;
}
int main() {
using namespace std;
// 这个 double 专门为了 RT 而指定的, T1 和 T2 都可以通过调用参数推导出来
double a = ::max<double>(2, 3.2);
cout << "max(2, 3.2) = " << a << endl;
return 0;
}
我只想说 C++ 是真的骚。
编译器推理返回类型
如果返回类型依赖于模板参数,那么最简单的方法就是让编译器去推导类型。
C++ 14 中已经可以不用指定返回类型了,但是你还是要用 auto 来声明返回类型。
如下面的例子:
#include <iostream>
// 多个参数的函数木板
template<typename T1, typename T2>
auto max(T1 a, T2 b) {
using namespace std;
cout << "调用的自定义模板函数...... " << endl;
return b < a ? a : b;
}
int main() {
using namespace std;
// 这个 double 专门为了 RT 而指定的, T1 和 T2 都可以通过调用参数推导出来
auto a = ::max(2, 3.2);
auto b = ::max(5, 1.2);
cout << "max(2, 3.2) = " << a << endl;
cout << "max(5, 1.2) = " << b << endl;
return 0;
}
大爷的,我又要去学下 auto 是怎么用的。
使用了 auto 就可以不用 trailing of return type(返回类型后置),但是实际的返回类型还是要通过函数体中的返回语句来推导。
当然了,根据函数体来反推返回值类型要是可行的。
decltype
decay
看到这里有点懵逼。
公共类型作为返回类型
C++ 11 中,标准库提供了一种对多个类型生成共同类型的方法。
例如:
#include <iostream>
// 引入这个玩意儿生成共同类型
#include <type_traits>
// 骚里骚气啊
template<typename T1, typename T2>
std::common_type_t<T1, T2> max(T1 a, T2 b) {
using namespace std;
cout << "调用的自定义模板函数...... " << endl;
return b < a ? a : b;
}
int main() {
using namespace std;
// 这个 double 专门为了 RT 而指定的, T1 和 T2 都可以通过调用参数推导出来
auto a = ::max(2, 3.2);
auto b = ::max(5, 1.2);
cout << "max(2, 3.2) = " << a << endl;
cout << "max(5, 1.2) = " << b << endl;
return 0;
}
std::common_type 是一种 type trait,能够为返回类型生成一种结构。
typename std::common_type<T1, T2>::type // since C++ 11
而在 C++ 14 中
std::cmmon_type_t<T1, T2> // C++ 14 中的写法
服!气!
C++ 函数模板的返回类型如何确定?的更多相关文章
- C++函数模板
函数模板提供了一种函数行为,该函数行为可以用多种不同的类型进行调用,也就是说,函数模板代表一个函数家族,这些函数的元素是未定的,在使用的时候被参数化. 本文地址:http://www.cnblogs. ...
- C++ 初识函数模板
1. 前言 什么是函数模板? 理解什么是函数模板,须先搞清楚为什么需要函数模板. 如果现在有一个需求,要求编写一个求 2 个数字中最小数字的函数,这 2 个数字可以是 int类型,可以是 float ...
- C++函数重载和函数模板
1.函数重载 这是小菜鸟写的一个例子. 函数重载应该注意以下几点: 1.1重载函数有类似的功能: 1.2只能以参数的类型(形参个数和类型)来重载函数, int max(int a,int b);flo ...
- C++_进阶之函数模板_类模板
C++_进阶之函数模板_类模板 第一部分 前言 c++提供了函数模板(function template.)所谓函数模板,实际上是建立一个通用函数,其函数类型和形参类型不具体制定,用一个虚拟的类型来 ...
- C++复习:函数模板和类模板
前言 C++提供了函数模板(function template).所谓函数模板,实际上是建立一个通用函数,其函数类型和形参类型不具体指定,用一个虚拟的类型来代表.这个通用函数就称为函数模板.凡是函数体 ...
- C++解析(26):函数模板与类模板
0.目录 1.函数模板 1.1 函数模板与泛型编程 1.2 多参数函数模板 1.3 函数重载遇上函数模板 2.类模板 2.1 类模板 2.2 多参数类模板与特化 2.3 特化的深度分析 3.小结 1. ...
- [转]C++函数模板与模板函数
1.函数模板的声明和模板函数的生成 1.1函数模板的声明 函数模板可以用来创建一个通用的函数,以支持多种不同的形参,避免重载函数的函数体重复设计.它的最大特点是把函数使用的数据类型作为参数. ...
- C++模板之函数模板实例化和具体化
模板声明 template<typename/class T>, typename比class最近后添加到C++标准. 常规模板,具体化模板,非模板函数的优先调用顺序. 非模板函数(普通 ...
- C++泛型编程之函数模板
泛型语义 泛型(Generic Programming),即是指具有在多种数据类型上皆可操作的含意.泛型编程的代表作品 STL 是一种高效.泛型.可交互操作的软件组件. 泛型编程最初诞生于 C++中, ...
随机推荐
- VMware5.5-vCenter的安装准备及安装
vSphere 最近公司来了新同事,为了帮助他尽快熟悉VM-vsphere,一块复习了下,并把实验总结为文档. 声明:本例是以王隆杰老师的vsphere5.5教程为基础和线索进行的,由于时间匆忙,可能 ...
- python基础一 ------如何根据字典值对字典进行"排序"
需求:{姓名:成绩} 的字典,按成绩进行排序 方法一:转化为元组,(91,"张三")的形式 ,用sorted()函数进行排序 方法二 :设置sorted() 中key的参数的值 # ...
- Git在eclipse中的使用,克隆导入eclipse项目
一 Eclipse 安装EGit 1)安装 Eclipse Juno 版后已经集成了EGit,可以通过如下地址安装:http://download.eclipse.org/egit/upda ...
- Android 如何判断指定服务是否在运行中 “Service”
如何判断一个服务是否正在运行中: /** * 判断某个服务是否正在运行的方法 * * @param mContext * @param serviceName 是包名+服务的类名 * @return ...
- 开源评测系统hustoj-代码解读
非常感谢zhblue贡献了这么美丽的代码 为了开发适合自己学校的oj,努力研读代码中,不断的百度,调试,测试 对ubutun,linux的各种文件系统,进程系统,c编程都学习了不少 给大家分享下,希望 ...
- Dijkstra求次短路
#10076.「一本通 3.2 练习 2」Roadblocks:https://loj.ac/problem/10076 解法: 次短路具有一种性质:次短路一定是由起点到点x的最短路 + x到y的距离 ...
- Mac下nodeJS初体验
Mac下nodeJS初体验 这两天博主出门在外,抽空体验一下大名鼎鼎的node 安装 brew install node 安装测试 $ node -v v8.4.0 运行本地脚本 用文本编辑器编辑一段 ...
- CSS之优先级
css的优先级 所谓CSS优先级,即是指CSS样式在浏览器中被解析的先后顺序. 样式表中的特殊性描述了不同规则的相对权重,它的基本规则是: 1 内联样式表的权值最高 sty ...
- JS_高程6.面向对象的程序设计(2)创建对象_3 构造函数存在的问题
# 上次讲到用构造函数的模式来创建对象,相对于工厂模式,解决可对象识别的问题. function Person(name,age,job){ this.name=name; this.age=age; ...
- Selenium 3 + BrowserMobProxy 2.1.4 模拟浏览器访问 (含趟坑)
背景 Selenium 是一个Web自动化测试的组件,可基于WebDriver去控制弹出浏览器去做一系列Web点击或行为测试(当然也可以去做一些邪恶的事..),减少重复人工网页测试的开销.Browse ...