[Effective Modern C++] Item 1. Understand template type deduction - 了解模板类型推断
条款一 了解模板类型推断
基本情况
首先定义函数模板和函数调用的形式如下,在编译期间,编译器推断T和ParamType的类型,两者基本不相同,因为ParamType常常包含const、引用等修饰符
template<typename T>
void f(ParamType param); // 函数模板形式
f(expr); // 函数调用
存在T的类型即为expr类型的情况,如下T为int
templat<typename T>
void f(const T& param);
int x = ;
f(x); // T -> int
但是T的类型的推断不仅与expr有关,还和ParamType有关。有如下三种情况:
- ParamType是指针或引用类型,但不是通用引用(universal reference)
如果expr是引用类型,则忽略引用部分
然后通过模式匹配expr与ParamType来决定T
向函数模板传递一个const对象是合法的,T会添加对应的const,如下所示
template<typename T>
void f(T& param); int x = ;
const int cx = x;
const int& rx = x; f(x); // T -> int, param -> int&
f(cx); // T -> const int, param -> const int&
f(rx); // T -> const int, param -> const int&
以上示例演示的是左值引用形参,对于右值应用也一样,当然只有右值实参能传入右值引用形参,但对于类型推断没有影响
const T&的情况
template<typename T>
void f(const T& param); int x = ;
const int cx = x;
const int& rx = x; f(x); // T -> int, param -> int&
f(cx); // T -> int, param -> const int&
f(rx); // T -> int, param -> const int&
T*的情况
template<typename T>
void f(T* param); int x = ;
const int *px = &x; f(&x); // T int, param -> int*
f(px); // T const int, param -> const int*
- ParamType是通用引用
如果expr是左值,则T与ParamType被推断为左值引用。这非常不同寻常,首先这是模板类型的唯一情境T被推断为引用,然后即使ParamType的语法是一个右值引用,它推断出的类型也是左值引用
如果expr是右值,则适用情况一的规则
template<typename T>
void f(T&& param); int x = ;
const int cx = x;
const int& rx = x; f(x); // x -> lvalue, T -> int&, param -> int&
f(cx); // x -> lvalue, T -> const int&, param -> const int&
f(rx); // x -> lvalue, T -> const int&, param -> const int&
f(); // 27 -> rvalue, T -> int, param -> int&&
当使用通用引用的时候,左值实参与右值实参的类型推断不同,但是对于非通用引用则没有区别
- ParamType既不是指针又不是引用
如果expr是引用类型,则忽略引用部分
在忽略引用部分后,如果expr是const或volatile,也同时忽略
template<typename T>
void f(T param); int x = ;
const int cx = x;
const int& rx = x; f(x); // T -> int, param -> T
f(cx); // T -> int, param -> T
f(rx); // T -> int, param -> T
由于是拷贝,实参的const不再生效
以下是一个特殊情形分析
template<typename T>
void f(T param); const char* const ptr = "Fun with pointers"; f(ptr); // T -> const char*, param -> const char*
ptr是按值传递,则ptr的const需要舍弃,则param的类型为const char*
数组实参
尽管数组类型与指针类型在有时候可以转换(许多情境下数组退化为指向第一个元素的指针,array-to-pointer decay rule),但依旧值得探讨一些细节问题。
实际上没有数组类型的形参,其会转换为指针
一般数组情形
template<typename T>
void f(T param); const char name[] = "J. P. Briggs"; f(name); // T -> const char*, param -> const char*
引用数组情形
template<typename T>
void f(T& param); const char name[] = "J. P. Briggs"; f(name); // T -> const char[13], param -> const char(&)[13]
以下函数在编译器能直接获取已知数组的长度
template<typename T, std::size_t N>
constexpr std::size_t arraySize(T (&)[N]) noexcept {
return N;
}
函数实参
函数类型也会退化为函数指针类型,其规则和数组相同
void someFunc(int, double); template<typename T>
void f1(T param); template<typename T>
void f2(T& param); f1(someFunc); // T -> void (*)(int, double), param -> void (*)(int, double)
f2(someFunc); // T -> ?, param -> void (&)(int, double)
总结
- 在模板类型推断过程中,引用实参被当做非引用处理,所以他们的引用性被忽略
- 当推断通用引用的形参时,左值实参特殊对待
- 当推断传值形参的类型时,const、volatile的实参忽略其const、volatile
- 在模板类型推断的过程中,数组或函数的实参退化为指针,除非他们被用来初始化引用
[Effective Modern C++] Item 1. Understand template type deduction - 了解模板类型推断的更多相关文章
- [Effective Modern C++] Item 2. Understand auto type deduction - 了解auto类型推断
条款二 了解auto类型推断 基础知识 除了一处例外,auto的类型推断与template一样.存在一个直接的从template类型推断到auto类型推断的映射 三类情况下的推断如下所示: // ca ...
- [Effective Modern C++] Item 3. Understand decltype - 了解decltype
条款三 了解decltype 基础知识 提供一个变量或者表达式,decltype会返回其类型,但是返回的内容会使人感到奇怪. 以下是一些简单的推断类型: ; // decltype(i) -> ...
- 现代C++之理解模板类型推断(template type deduction)
理解模板类型推断(template type deduction) 我们往往不能理解一个复杂的系统是如何运作的,但是却知道这个系统能够做什么.C++的模板类型推断便是如此,把参数传递到模板函数往往能让 ...
- [Effective Modern C++] Item 6. Use the explicitly typed initializer idiom when auto deduces undesired types - 当推断意外类型时使用显式的类型初始化语句
条款6 当推断意外类型时使用显式的类型初始化语句 基础知识 当使用std::vector<bool>的时候,类型推断会出现问题: std::vector<bool> featu ...
- [Effective Modern C++] Item 4. Know how to view deduced types - 知道如何看待推断出的类型
条款四 知道如何看待推断出的类型 基础知识 有三种方式可以知道类型推断的结果: IDE编辑器 编译器诊断 运行时输出 使用typeid()以及std::type_info::name可以获取变量的类型 ...
- 《Effective Modern C++》翻译--条款2: 理解auto自己主动类型推导
条款2: 理解auto自己主动类型推导 假设你已经读过条款1关于模板类型推导的内容,那么你差点儿已经知道了关于auto类型推导的所有. 至于为什么auto类型推导就是模板类型推导仅仅有一个地方感到好奇 ...
- [Effective Modern C++] Item 5. Prefer auto to explicit type declarations - 相对显式类型声明,更倾向使用auto
条款5 相对显式类型声明,更倾向使用auto 基础知识 auto能大大方便变量的定义,可以表示仅由编译器知道的类型. template<typename It> void dwim(It ...
- Effective Modern C++ Item 27:重载universal references
假设有一个接收universal references的模板函数foo,定义如下: template<typename T> void foo(T&& t) { cout ...
- [Effective Modern C++] Item 7. Distinguish between () and {} when creating objects - 辨别使用()与{}创建对象的差别
条款7 辨别使用()与{}创建对象的差别 基础知识 目前已知有如下的初始化方式: ); ; }; }; // the same as above 在以“=”初始化的过程中没有调用赋值运算,如下例所示: ...
随机推荐
- html布局
1.div <!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8 ...
- linux下python3连接mysql数据库
python语言的3.x完全不向前兼容,导致我们在python2.x中可以正常使用的库,到了python3就用不了了.比如说mysqldb 1.安装pymysql pymysql就是作为python3 ...
- 关于thinkphp中Hook钩子的解析
在tp框架下的Library/Think 下有一个Hook类,这个是用来以插件形式来实例化类并且执行方法的 static private $tags = array(); 这里有一个 ...
- BeanUtils包的学习
BeanUtils支持八种基本数据类型(int double short char byte float boolean long)的反射,对于日期需要提前注册DateLocalConvert获取转换 ...
- 纯js实现积木(div)拖动效果
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- JS+html实现简单的飞机大战
摘要:通过原生的js+html实现简单的飞机大战小游戏效果,如图所示: 实现代码如下: 1.自己的飞机实现 飞机html: <!DOCTYPE html> <html lang=&q ...
- ubuntu下安装fiddler
因为工作中需要用到fiddler工具 现在工作环境迁移到ubuntu14 下 发现fiddler只支持windows网上也有很多推荐 号称可以代替fiddler 但因为功能使用上比较习惯 并 ...
- Linux vps无法发送邮件
首先安装sendmail软件...yum install sendmail /etc/init.d/php-fpm restart 来检查下sendmail是否正常运行 /etc/init.d/sen ...
- USB系列之三:从你的U盘里读出更多的内容
U盘是我们最常使用的一种USB设备,本文继续使用DOSUSB做驱动,试图以读取扇区的方式读取你的U盘.本文可能涉及的协议可能会比较多. 一.了解你的U盘 首先我们用上一篇文章介绍的程序usbvi ...
- Qt带来的是更加低廉的开发成本和学习成本,对于很多小公司而言,这种优势足以让他们获得更大的利润空间 good
不能单纯从技术上来看待这个问题,Qt本来是小众的开发平台,个人认为,它的出现只是解决特性场景的特定问题,Qt带来的是更加低廉的开发成本和学习成本,对于很多小公司而言,这种优势足以让他们获得更大的利润空 ...