C++关键字decltype

decltype的使用

引入关键字decltype的原因是有时候我们仅仅希望使用表达式的类型而不使用它的值,可以通过decltype,编译器分析表达式并得到它的类型,但并不实际计算表达式的值

基础

double f();
int main() {
	int temp = 0;
	decltype(temp) a = 0;		//a的类型为int
	decltype(f()) b = 1.0;		//b的类型为double,尽管函数f()并没有定义
								//编译器并不实际调用函数,只是分析
}

decltype与const、引用

decltype和auto处理顶层const以及处理引用的方式不同,如果decltype使用的表达式是一个变量,则decltype返回该变量的类型包括顶层const和引用

int i = 0, &j = i;
decltype(j) h = i;			//h的类型是int&
const int ci = 0, &cj = ci;
decltype(ci) x = 0;			//x的类型是const int
decltype(cj) y = x;			//y的类型是const int&,y必须绑定到int或者const int变量上
int *const pi = &i;
const int *const cpi = &ci;
decltype(pi) dpi = &i;		//dpi的类型为int *const
decltype(cpi) dcpi = &ci;	//dcpi的类型为const int *const

骚操作

decltype的结果类型与表达式形式密切相关,对于decltype所用的表达式来说,如果变量名加上了一对括号,则得到的类型与不加括号时会有所不同,如果decltype使用的是一个不加括号的变量,则得到的结果就是该变量的类型;如果给变量加上一层或多层括号,编译器就会把它当成是一个表达式。变量是一种可以作为赋值语句左值的特殊表达式,这样的decltype就会得到引用类型。
**切记:**decltype((variable))(注意是双层括号)得到的结果永远是引用,而decltype(variable)只有当variable本身是引用时才得到引用。

int i = 42, j = 0;
decltype(i) e;			//e的类型为int(未初始化)
decltype((i)) d = j;	//d的类型为int&,必须初始化

上述来自《C++ Primer》第五版,我不是很理解,看了C++decltype((i))为什么是引用所说的,稍微理解

  • decltype((i)) --> (i)
  • decltype(i) --> i

第一个decltype处理的是(i),第二个处理的是i
在C++中,第一个是“lvalue表达式”,第二个是“一个变量”
因为是“lvalue表达式”,decltype会理解为引用。

这篇博客对decltype推导规则的总结很到位

decltype推导四规则
  1. 如果e是一个没有带括号的标记符表达式或者类成员访问表达式,那么的decltype(e)就是e所命名的实体的类型。此外,如果e是一个被重载的函数,则会导致编译错误
  2. 否则 ,假设e的类型是T,如果e是一个将亡值,那么decltype(e)为T&&
  3. 否则,假设e的类型是T,如果e是一个左值,那么decltype(e)为T&
  4. 则,假设e的类型是T,则decltype(e)为T

标记符指的是除去关键字、字面量等编译器需要使用的标记之外的程序员自己定义的标记,而单个标记符对应的表达式即为标记符表达式。具体案例如下

int i = 4;
double dd = 0.0;
int arr[5] = { 0 };
int *ptr = arr;
struct S{ double d;}s ;
void Overloaded(int);
void Overloaded(char);//重载的函数
int && RvalRef();
const bool Func(int);

//规则一:推导为其类型
decltype (arr) var1; //int[5] 标记符表达式

decltype (ptr) var2;//int*  标记符表达式

decltype(s.d) var3;//double 成员访问表达式

//decltype(Overloaded) var4;//重载函数。编译错误。

//规则二:将亡值。推导为类型的右值引用。

decltype (RvalRef()) var5 = 1;

//规则三:左值,推导为类型的引用。

decltype ((i)) var6 = i;     //int&

decltype (true ? i : i) var7 = i; //int&  条件表达式返回左值。

decltype (++i) var8 = i; //int&  ++i返回i的左值,注意这里并不会真的执行++i

decltype(arr[5]) var9 = i;//int&. []操作返回左值

decltype(*ptr)var10 = i;//int& *操作返回左值

decltype("hello") var11 = "hello";	//const char(&)[6]  字符串字面常量为左值,且为const左值。
									//字符串字面值常量是个左值,且是const左值,而非字符串字面值常量则是个右值。


//规则四:以上都不是,则推导为本类型

decltype(1) var12;//const int

decltype(Func(1)) var13=true;//const bool

decltype(i++) var14 = i;//int i++返回右值 注意这里并不会真的执行i++

C++标准库<type_traits>提供三个模板类,可以判断是否是左值引用还是右值引用、引用类型。is_rvalue_reference,is_lvalue_reference,is_reference
使用方法:cout << std::is_lvalue_reference<decltype(“hello”)>::value << endl;输出为1。
我认为作为简单的使用可以按如下推导,decltype使用的包括变量、返回左值的表达式、返回右值的表达式,使用变量时,按照变量的原本类型推导,包括引用和const属性,使用返回左值的表达式时,推导为左值表达式类型的引用;使用右值表达式时,推导为右值的类型。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值