[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 在以“=”初始化的过程中没有调用赋值运算,如下例所示: ...
随机推荐
- 类似QQ侧滑菜单功能实现
之前的那文章简单实现了菜单侧拉功能,但是做不到像QQ那样导航条和tabBar一起移动...之后在网上找资料,有了思路,就自个写了个demo试试水. 先创建QHLMainController控制器,并把 ...
- swift——设置navigationitemtitle的内容以及格颜色
1.用UILabel,自定义整个titleview // var TitleText = UILabel() self.TitleText.frame = CGRectMake(0, 0, 100, ...
- K - Ignatius and the Princess IV
Description "OK, you are not too bad, em... But you can never pass the next test." ...
- YII Framework学习教程-YII的Model-开发规范-路径别名-命名空间
到这里,大概的YII开发已经基本可以,但是下面要将的所有课程,学完之后可以让你更爱YII.下面的教程是讲的MVC的M,model.数据,业务,代码的集中地区.所以开始之前,学学开发规范-路径别名-命名 ...
- 用CSS截断字符串
方法一: <div style="width:300px; overflow:hidden; text-overflow:ellipsis; white-space:nowrap;&q ...
- HTML5学习笔记一:新增主体结构元素
Dreamweaver快捷键: 属性面板:Ctrl+F3 新建文档:Ctrl+N 选择用网页查看:F12 新增的主体结构元素: section元素(例子如下): <!DOCTYPE HTML&g ...
- TreeSet与HashSet的区别
Set是java中一个不包含重复元素的collection.更正式地说,set 不包含满足 e1.equals(e2) 的元素对 e1 和 e2,并且最多包含一个 null 元素.正如其名称所暗示的, ...
- SpringMVC原理+流程图
SpringMVC工作原理:整个处理过程从一个HTTP请求开始:1)DispatcherServlet接收到请求后,根据对应配置文件中配置的处理器映射,找到对应的处理器映射项(HandlerMappi ...
- 开源C/C++网络库比较
在开源的C/C++网络库中, 常用的就那么几个, 在业界知名度最高的, 应该是ACE了, 不过是个重量级的大家伙, 轻量级的有libevent, libev, 还有 Boost的ASIO. ACE是一 ...
- 在一个exe文件中查找指定内容,找到则返回起始位置, 否则返回0
//在一个exe文件中查找指定内容,找到则返回起始位置, 否则返回0//如果某字符串, 直接传入字符串进来//如果要查找16进制,则用如下格式传参进来: #$1A#$2A#$3A function F ...