目录

一、decltype关键字

二、decltype的推导规则

1、表达式为单独变量

2、表达式为函数调用

3、表达式为左值,或者被()包围

三、 decltype的应用


在前面一章,小编已经对auto类型推导这个关键字进行了介绍,相信小伙伴们都知道了auto的用法以及限制了吧,不知道的小伙伴回头自己去搜索一下~~~。

一、decltype关键字

在这一章节中,小编要告诉你另外一个关键字,这个关键字也是作为类型推导用的,它是C++11新特性新加的一个关键字。这个关键字就是decltype,它和auto的功能一样,也是在编译器编译时期进行自动类型的推导。其实你可以把这个关键字看成是declare和type的缩写,这样是不是显得更加明确了呢?

看到这里,你肯定有一个疑问就是,为什么有了auto类型推导,还要有decltype这个关键字的出现呢?其实细心一点的话你可以发现auto关键字有一些限制,也就是上章节有讲到的限制,像定义变量的时候一定要初始化,不能作用于类的非静态变量。所以我们总结了auto并不是适用于所有的自动类型推导的场景,在某些特定环境下auto使用起来非常的不方便,甚至无法使用它,所以C++11新特性才会引出decltype这个关键字。

我们都知道auto定义变量的语法为:

auto serven_1 = 10;

可以看到auto是根据=右边的初始值来自动推导变量的类型,所以auto在定义的时候必须初始化;而同样decltype也有自己的语法,它的语法为:

decltype (exp) varname = value;

其中,varname表示变量名,value表示赋值变量的值,exp表示一个表达式,这就是和auto最大的区别了,decltype是根据表达式exp来自动推导出变量的类型,跟=右边的value没有关系,所以decltype在定义的时候可以不用初始化,因此,decltype定义变量也可以写成:

decltype (exp) varname;

这里需要注意exp表达式,通常一说到表达式,我们脑子里面想到的就是一个普通的表达式,像 x = 1等等,但是关键字decltype关键字中的表达式可以是复杂的表达式,复杂到你怀疑人生嘿嘿嘿。但是有一点需要注意的是必须保证表达式exp的结果是有类型的,不能是void。像exp在调用一个返回值类型为void的函数时,exp的结果也是void类型,此时编译器会给你直接报错了。

void show(){cout<<"三贝勒文子!"<<endl;
}
decltype (show()) serven_2;            // 编译器会一脸问号的问你,这是啥玩意???

如果使用下面的代码:

int show(){cout<<"Serven"<<endl;return 6;
}
​
int main(){int serven_1 = 1;decltype(serven_1) serven_2 = 3;decltype(show()) serven_3 = 5;cout<<serven_3<<endl;                  // 会打印5,但是不会打印函数show中的内容
}

decltype用法:

int serven_1 = 0;
decltype (serven_1) serven_2 = 1;        // serven_2被推导为 int
decltype (1.2) serven_3;                 // serven_3被推导为 double,不初始化也可以
decltype (serven_3 + 100) serven_4;      // serven_4被推导为 double

从上面的例子可以看到,decltype能够根据变量、字面量、带有运算符的表达式或者函数的返回类型推导出变量的类型。

二、decltype的推导规则

上面的例子让我们知道了decltype的一些初级用法,下面我们来了解一下decltype的高级用法吧,它的高级用法可以非常的复杂,当我们使用关键字来进行类型推导的时候,编译器有三个规则:

  • 如果表达式exp是一个不被括号()包围的表达式,或者是个类成员访问表达式,或者是一个单独的变量,那么decltype(exp)的类型就是和exp一致的,这应该不难理解;

  • 如果exp是函数调用,那么decltype(exp)的类型就和函数的返回值类型一致,但是注意一点就是函数的返回值不能是void;

  • 如果exp是一个左值,或者被括号()包围,那么decltype(exp)的类型就是exp的引用,假如exp的类型为T,那么decltype(exp)的类型就是T&。

1、表达式为单独变量

#include <QCoreApplication>
#include <iostream>
#include<string>
using namespace std;
​
​
class SERVEN_PAR{public:static int ser1;                    // 类静态变量在类中不能初始化string ser2;int ser3;float ser4;
};
​
int SERVEN_PAR::ser1 = 1;               // 初始化类的静态变量
​
int main(int argc, char *argv[])
{QCoreApplication a(argc, argv);
​int n = 0;const int& r = n;SERVEN_PAR SERVEN;decltype(n) b = n;                                      // n为int类型,b被推导为int类型decltype(r) c = n;                                      // r为const int&类型,c被推导为const int类型decltype(SERVEN_PAR::ser1) d = 0;                       // ser1位类的一个int类型成员,那么d被推导为int类型decltype(SERVEN.ser2) e = "https://www.baidu.com";      // ser2位类的一个string类型,那么e被推导为string类型return a.exec();
}

2、表达式为函数调用

#include <QCoreApplication>
#include <iostream>
#include<string>
using namespace std;
​
​
int& func_int_first(int, char);                 // 返回值为int&
int&& func_int_second(void);                    // 返回值为int&&
int func_int(double);                           // 返回值为int
​
const int& func_cint_first(int,int,int);        // 返回值为const int&
const int&& func_cint_second(void);             // 返回值为const int&&
​
​
int main(int argc, char *argv[])
{QCoreApplication a(argc, argv);
​int n = 10;decltype(func_int_first(100,'S')) b = n;        // b的类型为int&, 这里要赋初始值,因为int&引用需要初始化的,但是这里不能直接赋数值,因为这是左值引用decltype(func_int_second()) c = 0;              // c的类型为int&&,这里需要赋初始值,这是右值引用,所以可以直接赋数值decltype(func_int(10.5)) d = 0;                 // d的类型为 intdecltype(func_cint_first(1,2,3))  x = n;        // x 的类型为 const int &decltype(func_cint_second()) y = 0;             // y 的类型为 const int&&
​return a.exec();
}
​

值得注意的是:这里的表达式只使用了函数的返回类型,不会执行函数里面的函数体内容的。代码中decltype(func_int_first(100,'S')) b = n;b的类型为int&, 这里要赋初始值,因为int&引用需要初始化的,但是这里不能直接赋数值,因为这是左值引用。而decltype(func_int_second()) c = 0;c的类型为int&&,这里需要赋初始值,这是右值引用,所以可以直接赋数值。

3、表达式为左值,或者被()包围

#include <QCoreApplication>
#include <iostream>
#include<string>
using namespace std;
​
​
class SERVEN_PAR{
public:int x;
};
​
​
int main(int argc, char *argv[])
{QCoreApplication a(argc, argv);SERVEN_PAR SERVEN;/* 带有括号的表达式 */decltype(SERVEN.x) b;decltype((SERVEN.x)) c = b;/* 加法表达式 */int n = 0, m = 0;decltype(n+m) d = 0;           // n+m得到一个右值,复合推导规则一,推导结果为intdecltype(n = n+m) e = c;       // n=n+m得到一个左值,复合推导规则三,推导结果为intreturn a.exec();
}

​  上面的代码中包括了带有括号的表达式,和加法表达式两种,其中加法表达式里面分为了左值和右值,左值是指那些在表达式执行结束后依然存在的数据,也就是持久性的数据;右值是指那些在表达式执行结束后不再存在的数据,也就是临时性的数据,对表达式取地址操作,如果编译器报错了那就是右值,如果编译器不报错那就是左值。

三、 decltype的应用

我们知道了auto的使用比较简单,所以在一般的类型推导过程中,使用auto会比decltype更加方便。但是auto只能用于类的静态成员,不能用于类的非静态成员(普通成员),如果我们想推导非静态成员的类型的话,那么就得使用decltype关键字了,下面是一个模板的定义:

#include <vector>
using namespace std;
​
​
template <typename T>
class SERVEN_PAR {
public:void func(T& container) {m_it = container.begin();}
private:typename T::iterator m_it;  //注意这里
};
​
int main(){const vector<int> v;SERVEN_PAR<const vector<int>> obj;obj.func(v);return 0;
}

单独看SERVEN_PAR类中的m_it成员的定义,很难看出有什么错误,但是在使用SERVEN_PAR类的时候,如果传入一个const类型的容器,编译器马上就会弹出一大堆错误。原因就在于T::iterator并不能包括所有的迭代器类型,当T是一个const容器时,应用使用const_iterator。要想解决这个问题,在之前的 C++98/03 版本下只能想办法把 const 类型的容器用模板特化单独处理,增加了不少工作量,看起来也非常晦涩。但是有了 C++11 的 decltype 关键字,就可以直接这样写:

template <typename T>
class SERVEN_PAR {
public:void func(T& container) {m_it = container.begin();}
private:decltype(T().begin()) m_it;  //注意这里
};

欢迎关注小编的微信公众号 “三贝勒文子”,每天学习C++

C++11新特性之decltype类型推导相关推荐

  1. 二、C++11新特性:decltype类型推导

    目录 二.decltype类型推导 2.1. decltype decltype和auto的异同: 2.2.decltype的应用 ①.decltype和typedf/using合用 ②.deltyp ...

  2. C++11新特性之decltype关键字的使用

    一.decltype关键字介绍 decltype关键字与auto关键字相似,但又有不同之处:auto关键字是在编译时通过已经初始化的变量来确定auto所代表的类型.换句话说,auto修饰的表达式必须是 ...

  3. C++11新特性之POD类型

    POD(Plain Old Data)是C++中非常重要的一个概念,用来描述一个类型的属性其中Plain表示这个类型是个平凡的类型,Old表示其与C的兼容性.C++11中将POD划分为两个基本概念:平 ...

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

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

  5. 【C++面试宝典】C++11新特性知识总结

    目录 C++11新特性 auto自动类型推导 decltype类型指示符 nullptr常量 lambda表达式(匿名函数) 智能指针 auto_ptr unique_ptr shared_ptr w ...

  6. C++11新特性之long long类型

    今天让我们来看一下C++11新特性新增的数据类型吧,我们在编程经常会使用到类型来给变量定义,像int.double.char等等.但是你是否知道这些类型占用的字节数是多少吗? 今天小编带着你一起来看一 ...

  7. C++11新特性之二:decltype

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

  8. C++11之decltype类型推导(使用场景、推导四规则、cv限定符)

    系列文章 C++11之正则表达式(regex_match.regex_search.regex_replace) C++11之线程库(Thread.Mutex.atomic.lock_guard.同步 ...

  9. C++11新特性decltype

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

最新文章

  1. js 的try catch应用
  2. 线性表的链式表示——循环链表
  3. C++虚函数的实现方式
  4. Enterprise Architecture 13 将顺序图自动转化为协作图
  5. 怎么考英语教师资格证
  6. SAP反记帐和红字冲销
  7. document.getElementById(billNo)的作用
  8. trigger 触发器(mysql)
  9. 【渝粤教育】国家开放大学2018年春季 8635-21T老年人中医体质辨识与养 参考试题
  10. Mongo 查询(可视化工具)
  11. 富人和穷人的对比图,时刻提醒自己!
  12. background 与backgroundcolor区别
  13. python tqdm自定义更新进度条
  14. 实现点击打卡_打卡APP哪家强?快来看!这里有一款超好用的轻量级免费的习惯养成APP!...
  15. 设计一个方法,可以实现任意范围内的随机数
  16. 杨辉三角程序(一步步优化)
  17. PE启动盘安装操作系统
  18. 如何设置华为悦盒Ubuntu系统的无线WiFi自动连接
  19. 网易云音乐 最美的评论
  20. firefox插件下载失败

热门文章

  1. Node.js + Vue.js 全栈开发王者荣耀手机端官网和管理后台
  2. 2018-暑期实习生-自然语言处理算法岗-面试题
  3. centos8恢复出厂设置_使用CentOS / RHEL 8进行初始服务器设置
  4. Java线程池详细介绍与使用
  5. jquery validation engine ajax验证,jquery.validationEngine 验证 AJAX 不起作用解决方法
  6. 记录Ubuntu下安装使用QT
  7. Linux系统学习 -- 信号
  8. 信息论(熵、条件熵、联合熵、互信息)
  9. int转char类型
  10. ppt无法打开“XXX.docx代表的文件类型