C++11新增的关键字decltype(auto)

一、函数模板存在的类型问题

template<class T1,class T2>
void fun(T1 a, T2 b)
{
	(T1 or T2?)y = a + b;
}

语句y = a+b,其实我们并不知道y应该为什么类型,我们可以写成T1或者T2甚至可能是其类型。但是具体准确的写成哪一个呢?我们并不确定,因为用函数模板产生函数实体跟传入实参的类型有关,如果我们调用的时候是fun(int, double)那么按道理来说,结果应该是double,当然,如果我们用T1(在这里即int)也可以接收,只不过降低了结果的精确度。如果调用的时候是fun(short, int)那么结果准确类型的话,就是int类型的。甚至如果我们调用函数时fun(char , short),那么结果准确类型应该是int类型(在这里加法运算会导致自动整数提升),这个时候既不是T1类型,也不是T2类型。除此之外,我们可能重载结构体或者类的"+"运算符,这会导致结果的类型更复杂多变。
C++11提出decltype关键字来解决这个问题。

二、decltype关键字

1.decltype基本用法和作用

int main()
{
	int x = 10;
	decltype(x) y1;//int类型

	short a = 2;
	char b = 1;
	decltype(a + b) y2;//int类型

	double c = 1;
	decltype(x + c) y3;//double类型


	return 0;
}

相当于decltype会自动推演类型,这一点我觉得和auto挺相像的。
那么我们的模板类就可以写成下面这样。

template<class T1,class T2>
void fun(T1 a, T2 b)
{
	 decltype(a+b) y = a + b;
}

这样y类型就是精确的类型了。
即decltype的使用格式是:decltype (expression) y;即定义一个变量y,类型和expression类型相同。expression可以是变量也可以是表达式。
编译器为了确定类型,会遍历一个核对表。

(1)如果expression是一个没有用括号括起来的标识符,则y与这个标识符类型相同。
举例:
int a;
decltype(a) y;
那么y就是和a类型相同,是int类型,包括const限定符。
举例:
const int a = 10;
decltype(a) y = 20;
decltype(a) y2(20);
注意上面decltype两种用法都可,但是一定得给初始值,因为y和y2也是const int类型,所以一定得给初始值。
(2)如果expression是一个左值并且用括号括起来了,那么y是这个标识符类型的引用。
举例:
int a;
decltype ((a)) y1(x1);
const int b = 10;
decltype((b)) y2(x2);
注意在这里y1就是类型为int& 类型的变量,x1是给y1初始化的,x1一定是个左值,且肯定不能是const。y2是类型为const int& 类型的变量,x2是给y2初始化的。
总结来说,expression再加个括号,那么decltype定义的变量类型就是expression类型的引用。引用我们都知道,一定需要初始化,初始化规则和我们平常使用引用初始化规则都一样。
(3)如果expression是一个函数调用,那么y与函数返回值类型相同,注意在这里并没有实施调用函数,只是编译器根据函数返回值类型推出来变量y应该的类型。
举例:
int fun(){return 0;}
decltype(fun()) y1;
decltype((fun())) y2;
注意y1和y2都是与fun函数返回类型相同的类型,即int。并不会因为多加了括号而变成int&。也就是上面的第二点对于函数并不适用。
(4)如果上面的都不符合,那么y和表达式expression类型相同。
举例:
int a = 10;
int& b = a;
int& c = a;
float d = 10;
decltype(a+b) y1;
decltype(b+c) y2;
decltype(a+d) y3;
a+b为int类型,所以y1是int类型。
b+c也是int类型,所以y2是int类型。
a+d是float类型,所以y3是float类型。
模板函数内部的变量类型用C++11新增的关键字decltype解决了。但是函数返回类型呢?
比如:

template<class T1,class T2>
? fun(T1 a,T2 b)
{
	return x + y;
}

函数返回值类型是什么?我们并不确定,刚才讲了decltype,难道可以这样写?:

template<class T1,class T2>
decltype(x+y) fun(T1 a,T2 b)
{
	return a + b;
}

答案是不行!因为此时还没有执行函数体,还不知道x和y变量,编译器看不见x和y,没办法使用。我们可以用auto。在这里auto是一个占位符,表示后置返回类型提供的类型。编译器会在编译期间将auto替换为正确类型。而decltype是关键字。这也是它们俩的不同点。

template<class T1,class T2>
auto fun(T1 a,T2 b)->decleype(x+y)
{
	return a + b;
}

这种写法是我在书上看的,但是我们其实不用这么麻烦,可以直接这样写:

template<class T1,class T2>
auto fun(T1 a,T2 b)
{
	return a + b;
}

因为auto是占位符,没有什么其他特殊作用,是编译器编译期间推导出来类型,将auto替换为了正确推导出来的类型。auto除了占位这个作用,其他事情都是编译器做的。
其实我们前面说的decltype做的事情,我们可以用auto占位,让编译器编译期间将auto替换掉。
比如:
int a = 10;
float b = 20;
auto x1 = a;
auto x2(a+b);
auto x2 = (a+b);
发现auto可以基本替代掉decltype的作用。只不过定义变量使用auto占位时,必须给出变量的初始值或者表达式,这样编译器才会有推导变量类型的依据,才能用正确类型替换掉占位符auto。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

孟小胖_H

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值