decltype与auto关键字一样,用于进行编译时类型推导。
decltype实际上有点像auto的反函数,auto可以让你声明一个变量,而decltype则可以从一个变量或表达式中得到类型,例如:

int x = 3;
decltype(x) y = x; 

有人会问,decltype的实用之处在哪里呢,假如有一个加工产品的函数模板:

template <typename Creator>
void processProduct(const Creator& creator) {  auto val = creator.makeObject();  // do somthing with val
} 

如果这个函数模板想把加工的产品作为返回值,该怎么办呢?我们可以这样写:

template <typename Creator>
auto processProduct(const Creator& creator) -> decltype(creator.makeObject()) {  auto val = creator.makeObject();  // do somthing with val  return val;
} 

decltype的历史

decltype是GCC实现的第一个C++ 11新特性。它实际上起源于一个相当古老的GNU扩展关键字——__typeof__。这个非标准关键字也能够在C语言中使用,GNU Compiler Collection的专业用户可能对它更熟悉一些。2008年,GCC 4.3.x就实现了这个特性,同时去除了__typeof__的一些缺点。现在,decltype和__decltype两个关键字在GCC中都适用;前者只能用在C++ 11模式下,后者可以同时应用于C++ 11和 C++ 98模式。__typeof__则已经停止使用。
下面来看看decltype的基本使用。简单来说,decltype关键字用于查询表达式的类型。不过,这只是其基本用法。当这个简单的表述同C++ 11的其它特性结合起来之后,一些意想不到的有趣用法就此产生。
decltype的语法是

decltype ( expression )

这里的括号是必不可少的。根据前面的说法,decltype的作用是“查询表达式的类型”,因此,上面语句的效果是,返回 expression 表达式的类型。注意,decltype 仅仅“查询”表达式的类型,并不会对表达式进行“求值”。

例子

先看一个基础的例子:

const int&& foo();
int i;
struct A { double x; };
const A* a = new A();decltype(foo())  x1;  // const int&&      (1)
decltype(i)      x2;  // int              (2)
decltype(a->x)   x3;  // double           (3)
decltype((a->x)) x4;  // double&          (4)

传统的__typeof__有一个颇为诟病的地方,在于不能很好地处理引用类型。而decltype则没有这个问题,decltype实际上更好地融入了 C++ 11 类型系统。来看一个比较复杂的例子:

int    i;
float  f;
double d;typedef decltype(i + f) type1;  // float
typedef decltype(f + d) type2;  // double
typedef decltype(f < d) type3;  // bool

上面的例子清楚看出,decltype 能够很好地处理类型转换这里问题。或许你会对上面代码中的 (4) 心生疑问。为什么decltype((a->x))会是double&?这是由decltype的推导规则决定的。
decltype推导三规则

1.如果e是一个没有带括号的标记符表达式或者类成员访问表达式(上例中的(2)和(3)),那么的decltype(e)就是e所代表的实体的类型。如果没有这种类型或者e是一个被重载的函数,则会导致编译错误。

2.如果e是一个函数调用或者一个重载操作符调用,那么decltype(e)就是该函数的返回类型(上例中的 (1))。

3.如果e不属于以上所述的情况,则假设e的类型是T:当e是一个左值时,decltype(e)就是T&;否则(e是一个右值),decltype(e)是T。上例中的(4)即属于这种情况。在这个例子中,e实际是(a->x),由于有这个括号,因此它不属于前面两种情况,所以应当以本条作为判别依据。而(a->x)是一个左值,因此会返回double &。

通过下面这段代码可以对三个推导规则做进一步了解:

#include <iostream>
#include <vector>
using namespace std;void Overloaded(int){ };
void Overloaded(char,char){ };//重载函数
const bool Func_1(int){ return true; };
const bool &Func_2(int){ return  true; };int main()
{int i = 4;const int j = 5;int arr[5] = { 0 };int *ptr = arr;struct S{ double d; }s;//规则一:推导为的其类型decltype(arr) var1;               //int[5] 标记符表达式decltype(ptr) var2;               //int *  标记符表达式decltype(s.d) var3;               //doubel 成员访问表达式//decltype(Overloaded(1)) var4;   //重载函数。编译错误。//规则二:推导为函数调用的返回类型decltype(Func_1(1)) var5 = true;  //bool,这是因为函数返回的是一个纯右值,对于纯右值,//只有类类型可以携带CV限定符,其他一般忽略掉CV限定符。decltype(Func_2(1)) var6 = true;  //const bool &//规则三:左值,推导为类型的引用decltype((i))var7 = i;            //int&decltype(true ? i : i) var8 = i;  //int&  条件表达式返回左值。decltype(++i) var9 = i;           //int&  ++i返回i的左值。decltype(arr[5]) var10 = i;       //int&  []操作返回左值decltype(*ptr)var11 = i;          //int&  *操作返回左值decltype("hello")var12 = "hello"; //const char(&)[6] 字符串字面常量为左值,且为const左值。//右值,则推导为本类型decltype(1) var13=10;             //int  decltype(i++) var14 = i;          //int i++返回右值   system("pause");return 0;
}

这里需要说明的是,字符串字面值常量是个左值,且是const左值,而非字符串字面值常量则是个右值。
这么多规则,对于我们写代码的来说难免太难记了,特别是规则三。我们可以利用C++11标准库中添加的模板类is_lvalue_reference来判断表达式是否为左值:

std::cout << std::is_lvalue_reference<decltype(++i)>::value << std::endl;

结果1表示为左值,结果为0为非右值。
同样的,也有is_rvalue_reference这样的模板类来判断decltype推断结果是否为右值。

参考链接:http://www.cnblogs.com/DswCnblog/p/6537411.html

C++11新特性之二:decltype相关推荐

  1. C++11新特性——auto和decltype

    一.auto和decltype 1.auto和decltype都是C++11新增的关键字,都用于类型自动推导. 类型格式 auto varname = value; //auto的语法格式 declt ...

  2. C++11新特性之decltype类型推导

    ​ 目录 一.decltype关键字 二.decltype的推导规则 1.表达式为单独变量 2.表达式为函数调用 3.表达式为左值,或者被()包围 三. decltype的应用 在前面一章,小编已经对 ...

  3. C++11新特性decltype

    该博文为原创文章,未经博主同意不得转载,如同意转载请注明博文出处 本文章博客地址:https://cplusplus.blog.csdn.net/article/details/105042574 C ...

  4. C++11新特性中的匿名函数Lambda表达式的汇编实现分析(二)

    2019独角兽企业重金招聘Python工程师标准>>> C++11新特性中的匿名函数Lambda表达式的汇编实现分析(一) 首先,让我们来看看以&方式进行变量捕获,同样没有参 ...

  5. C++ C++基础语法入门总结(二)引用-内联函数-C++11新特性

    C++基础语法入门总结 C++引用 再谈引用和指针 C++内联函数 附加C++11新特性 auto关键字 基于范围的for循环 指针空值nullptr C++引用 引用:就是某一变量(目标)的一个别名 ...

  6. C++11 新特性简介

    1.auto auto是旧关键字,在C++11之前,auto用来声明自动变量,表明变量存储在栈,很少使用.在C++11中被赋予了新的含义和作用,用于类型推断. auto关键字主要有两种用途:一是在变量 ...

  7. C++11新特性以及std::thread多线程编程

    一 .C++11新特性 1. auto 类型推导 1.1 当=号右边的表达式是一个引用类型时,auto会把引用抛弃,直接推导出原始类型: 1.2 当=号右边的表达式带有const属性时,auto不会使 ...

  8. 【C/C++】C++98基础上的C++11新特性

    一.新语法 1.自动类型推导auto auto的自动推导,用于从初始化表达式中推断出变量的数据类型. //C++98 int a = 10; string s = "abc"; f ...

  9. C++11新特性(原封不动转载待查)

    C++11标准发布已有一段时间了, 维基百科上有对C++11新标准的变化和C++11新特性介绍的文章. 我是一名C++程序员,非常想了解一下C++11. 英文版的维基百科看起来非常费劲,而中文版维基百 ...

最新文章

  1. 知识梳理——HTML篇
  2. Mysql的左外连接丶右外连接与内连接的区别
  3. Android keystore/Keymaster的代码导读
  4. 计算机辅助教学导学设计研究,《计算机辅助教学》实验报告
  5. 【Tools】MarkDown教程(六)-Markdown Reference
  6. 书评:卓有成效的ThoughtWorks程序员的45个习惯
  7. java下拉菜单_薪资对比:Java开发和web前端薪资哪个好
  8. 优化了MYSQL大量写入问题,老板奖励了1000块给我
  9. 使用原生js将轮播图组件化
  10. sql查询id最大的一行_mysql-聚合查询
  11. 换了一种管用pip安装方法,还有管用的python版hdf5(包名为h5py)安装方法
  12. 所闻所获3:下拉刷新控件1
  13. Scanf 用法和注意事项
  14. pl2303 USB转串口驱动
  15. vue将文件图片批量打包下载zip
  16. 连字符-后首字母的大小写
  17. Mac使用Microsoft-Remote-Desktop-for-Mac远程桌面Windows
  18. 一条简单 SQL 执行耗时超 1000ms,问题解决全过程!
  19. 三分钟了解JVM的垃圾回收和三色标记
  20. python opencv 锐化_图像增强、锐化,利用 Python-OpenCV 来实现 4 种方法!

热门文章

  1. 《App Store 审核指南》与《数据存储指南》
  2. Linux 传输文件
  3. xshell中查找命令_XShell命令大全
  4. 华为OD机试真题:分糖果-均分【2022 Q1 Q2 |200分】
  5. 方舟生存进化图鉴隐私条款
  6. 安全平台kb-security:Session劫持攻击【六】
  7. SS310L-ASEMI肖特基二极管SS310L
  8. win10激活出现错误0xc004f074 解决方案
  9. 建筑建材行业数字化建设解决方案
  10. JButton的左对齐实现