decltype类型声明

有时会遇到这样的情况:希望从表达式的类型推断出要定义的变量的类型,但不想用该表达式的值去初始化变量。为了满足这一需求,C++11引入了decltype,它的作用是选择并返回操作数的数据类型。在此过程中,编译器分析表达式并得到它的类型,却不实际计算表达式的值。

decltype(f()) sum = x;	//sum的类型就是函数f的返回类型,编译器并不实际调用函数f。

再者,decltype比较典型的用法就是与typedef/using的合用。在C++11的头文件中,我们常能看到以下的代码:

using size_t = decltype(sizeof(0));
using ptrdiff_t = decltype((int*)0 - (int*)0);
using nullptr_t = decltype(nullptr);

这种定义方式非常有意思,在一些常量、基本类型、运算符、操作符等都已经被定义好的情况下,类型可以按照规则被推导出。而使用using,就可以为这些类型取名。这就颠覆了之前类型拓展需要将拓展类型“映射”到基本类型的常规做法。

跟auto一样,由于应用广泛,所以使用decltype也有很多的细则条款需要注意。

当利用decltype(e)来获取类型时,编译器将依序判断以下四规则:

1)如果e是一个没有带括号的标记符表达式(id-expression)或者类成员访问表达式,那么decltype(e)就是e所命名的实体的类型。此外,如果e是一个被重载的函数,则会导致编译时错误。

如果参数是任何其他类型为T的表达式,且

2)如果e是一个亡值(xvalue),那么decltype(e)为T&&。

3)如果e是一个左值,则decltype(e)为T&。

4)如果e是一个纯右值,则decltype(e)为T。

这里需要解释下标记符表达式(id-expression)。基本上,所有除去关键字、字面量等编译器需要使用的标记之外的程序员自定义的标记(token)都可以是标记符(identifier)。而单个标记符对应的表达式就是标记符表达式。比如程序员定义了:

int arr[4];

那么arr是一个标记符表达式,而arr[3]+0,arr[3]等,则都不是标记符表达式。

上面的规则看起来复杂,但事实上,在实际应用中,最容易引起迷惑的只有规则1和3。可以通过下面的代码清单来加深下理解。

int i = 4;
int arr[5] = { 0 };
int *ptr = arr; struct S
{
double d;
}s; void Overloaded(int); //重载的函数 int && RvalRef(); //规则1:单个标记符表达式及访问类成员,推导为本类型
decltype(i) var0; //标记符表达式
decltype(arr) var1; //int[5],标记符表达式
decltype(ptr) var2; //int *,标记符表达式
decltype(s.d) var4; //double,成员访问表达式
decltype(ptr) var2; //无法编译,是个重载函数 //规则2:亡值推导为类型的右值引用
decltype(RvalRef()) var6 = 1; //int&& //规则3:左值推导为类型的引用
decltype((i)) var8 = i; //int&, 带圆括号的左值
decltype(arr[3]) var10 = i; //int&, []操作返回左值
decltype(*ptr) var11 = i; //int&,*操作返回左值 //规则4:纯右值,推导为本类型
decltype(1) var13; //int,除字符串外字面常量为右值

需要注意规则3例子中(i)不是一个标记符表达式,但却是一个左值表达式,(可以有具名的地址),

因此按照规则3,其类型是一个int的引用。这是与auto的一处重要区别————decltype的结果类型与表达式形式相关。

此外,decltype处理顶层const,和引用的方式与auto有些不同。如果decltype使用的表达式是一个变量,则decltype返回该变量的类型(包括顶层const和引用在内),而auto中会忽略掉顶层const和引用。

int i = 0;
const int ci = i, &cr = ci;
decltype(ci) b = 0; //b:const int
decltype(cr) c = b; //c:const int &,因为cr就是引用类型

最新文章

  1. 自己写了一个无缝滚动的插件(jQuery)
  2. Android 控件属性介绍
  3. 分享Kali Linux 2016.2第45周镜像
  4. Linux字符设备
  5. (一)win7下cocos2d-x 21 + vs2010
  6. Delphi dbf文件如何定位记录(即设置Table的RecNum属性来移动到该记录号)
  7. 蒙地卡罗法求 PI
  8. Linux下软件安装方法即路径设置
  9. OpenJudge计算概论-求出e的值
  10. 3.5html学习笔记之框模型,盒子模型
  11. 【转载】经典漫画讲解HDFS原理
  12. tar 解压缩命令
  13. python基础知识八
  14. javascript新的原生态API
  15. Ubuntu下的第一个博客
  16. 关于云Linux部署tomcat服务器(Maven的多模块war包)
  17. 怎么轻松学习JavaScript
  18. 分布式理论(四)—— 一致性协议之 3PC
  19. 【咸鱼教程】EUI多图片滑动组件ScrollView
  20. 2018.08.28 洛谷P3345 [ZJOI2015]幻想乡战略游戏(点分树)

热门文章

  1. php 建立 搜索 分词树
  2. golang文件传输服务
  3. WP8.1学习系列(第十七章)——交互UX之输入和反馈模式
  4. DELPHI XE Android 开发笔记
  5. 【linux系列】cenos7安装jdk
  6. vue经验 - 细节小知识点汇总(更新中...)
  7. Java虚拟机七 虚拟机监控
  8. mysql判断一个字符串是否包含某几个字符
  9. 利用 :first-child 和 :nth-last-child 确定子元素数目
  10. Jmeter与Jenkins结合进行Web接口测试