[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 在以“=”初始化的过程中没有调用赋值运算,如下例所示: ...
随机推荐
- Spark集群搭建简要
Spark集群搭建 1 Spark编译 1.1 下载源代码 git clone git://github.com/apache/spark.git -b branch-1.6 1.2 修改pom文件 ...
- mysql按月,按日分组统计数据
group by DATE_FORMAT(createtime,'%Y-%m');//按月统计数据 group by DATE_FORMAT(createtime,'%Y-%m-%d');//按天统计 ...
- XHTML 结构化:使用 XHTML 重构网站
http://www.w3school.com.cn/xhtml/xhtml_structural_01.asp 我们曾经为本节撰写的标题是:"XHTML : 简单的规则,容易的方针.&qu ...
- Mvc音乐商店demo的ajax异步删除功能总结
刚刚从学校出来参加工作,没啥工作经验,所以各位大神们不要嘲笑哈! 来公司后要进行培训,给我们的作业中有一个使用 dapper+mvc+ajax+SQL Server 2008,来实现一个音乐商店的de ...
- c#或获取系统的特殊路径,如我的文档等
Console.WriteLine(System.Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments)); System.E ...
- css pre如果同时运用了css的border-radius、 overflow两个属性且标签中内容太多时,外部div滚动条在firefox下滚动时很卡
pre如果同时运用了css的border-radius. overflow两个属性且标签中内容太多时,外部div滚动条在firefox下滚动时很卡. 解决方法:去掉css中border-radius. ...
- 使用ARM模板部署自动扩展的Linux VMSS(1)
在Azure之前的ASM版本或者经典模式中,用户使用Azure Website,Azure Cloud Service等PAAS服务,可以实现一定程度上的自动扩展(auto scaling),但有着诸 ...
- 如何使用fiddler进行android手机测试
一.什么是Fiddler Fiddler是一个http协议调试代理工具,它能够记录并检查所有你的设备和互联网之间的http通讯,设置断点,查看所有的“进出”Fiddler的数据,并且可以胡乱修改. F ...
- 关于文字颜色/图片背景---selector状态列表
文字颜色 android:textColor="@style/style_name" ----------------------------------widget 图片背景 a ...
- Qt中事件处理的方法(三种处理方法,四种覆盖event函数,notify函数,event过滤,事件处理器。然后继续传递给父窗口。可观察QWidget::event的源码,它是虚拟保护函数,可改写)
一.Qt中事件处理的方式 1.事件处理模式一 首先是事件源产生事件,最后是事件处理器对这些事件进行处理.然而也许大家会问, Qt中有这么多类的事件,我们怎么样比较简便的处理每个事件呢?设想,如果是 ...