类型别名声明using、类型说明符auto、类型指示符decltype、尾置返回类型->

  • using

using的用法:

using 类型名 = 定义的类型的别名;
using SI = Sales_item;  //SI是Sales_item的同义词

指针、常量和类型别名:如果某个类型别名指代的是复合类型或常量,那么把它用到声明语句里就会产生意想不到的后果
例如下面的声明语句用到了类型pstring,它实际上是类型char*的别名

typedef char* pstring;
const pstring cstr = 0;  //cstr是指向char的常量指针 而不是指向常量char的指针
const pstring* ps;  //ps是一个指针,它的对象是指向char的常量指针

上述俩条声明语句的基本类型都是const pstring,和过去一样,const是对给定的类型的修饰,pstring实际上是指向char的指针,也就是const修饰的是指针因此,const pstring就是指向char的常量指针而不能直接把类型别名替换来思考,所以它不是指向常量字符的指针,遇到一条使用了类型别名的声明语句时,人们往往会错误地尝试把类型别名替换成它本来的样子,以理解
该语句的含义。const char* cstr = 0;    //是对const pstring cstr的错误理解
       再强调一遍:这种理解是错误的,声明语句中用到了pstring时,其基本数据类型是指针,可是用char*重写了声明语句后,数据类型就变成了char*,*成了声明符的一部分。这样改写的结果是,const char成了基本数据类型,前后俩种声明含义截然不同,前者声明了一个指向char的常量指针,改写后的形式则声明了一个指向const char的指针

返回数组指针:因为数组不能被拷贝,所以函数不能返回数组,不过函数可以返回数组的指针或引用,可以使用类型别名来简化

typedef int arrT[10]; //arrT是一个类型别名,它表示的类型是含有10个整数的数组
using arrT = int[10]; //arrT的等价声明
arrT* func(int i);	  //func返回一个指向含有10个整数的数组的指针

 

  • auto

auto:用auto就能让编译器替我们去分析表达式所属的类型,auto定义的变量必须有初始值,使用auto也能在一条语句中声明多个变量,因为一条声明语句中只能有一个基本数据类型,所以该语句中所有变量的初始基本数据类型都必须一样

auto i = 0, *p = &i;  //正确 i是整数、p是整型指针
auto sz = 0, pi = 3.14; //错误 sz和pi的类型不一致

复合类型、常量和auto:首先正如我们所熟知的,使用引用其实是使用引用的对象,特别是当引用被用作初始值时,真正参与初始化的其实是引用对象的值,此时编译器以引用对象的类型作为auto的类型
所以想用auto来推导出引用类型时,必须适用auto&,否则推导出的类型是非引用类型的

int i = 0, &r = i;
auto a = r;  //a是一个整数(r是i的别名,而i是一个整数)
	int i = 0, &r = i;
	auto a = r;          //发生拷贝a为r的一个拷贝
	auto& a2 = r;        //ar为r的一个别名
	r += 10;
	cout << i << endl;   //10
	cout << r << endl;   //10
	cout << a << endl;   //0
	cout << a2 << endl;  //10

如图所示a是一份拷贝,它的地址和r、i、a2的地址不同。

auto不能推导引用类型但是可以推导出指针类型

int * foo(int* i)
{
	return i;
}

int main()
{
	auto p1 = new int(1000);     //p1为int*类型
	cout << p1 << endl;			 //打印为地址
	cout << *p1 << endl;		 //1000
	int *p2 = new int(100);
	auto p = foo(p2);			 //p为int*类型
	*p2 = 200;
	cout << *p << endl;			 //200
}

auto一般会忽略掉顶层const,同时底层const则会保留下来

const int ci = i, &cr = ci;
auto b = ci; //b是一个整数(ci的顶层const特性被忽略掉了)
auto c = cr; //c是一个整数(虽然cr是底层const,但真正参与初始化的是引用对象(ci)的值,ci本身是一个顶层const
auto d = &i; //d是一个整型指针
auto e = &ci;//e是一个指向整数常量的指针(对常量对象取地址是一种底层const)

如果希望推断出的auto类型是一个顶层const需要明确指出
 

const auto f = ci;		//ci的推演类型是int,f是const int

 

  • decltype 

有时会遇到这种情况:希望从表达式的类型推断出要定义的变量的类型,但是不想用该表达式的值初始化变量。decltype的作用是选择并返回操作数的数据类型,在此过程中,编译器分析表达式并得到他的类型,却不实际计算表达式的值

decltype(f())sum = x;  //sum的类型就是函数f的返回类型

换句话说,编译器为sum指定的类型就是假如f被调用的话会返回的那个类型
decltype 处理顶层const和引用的方式与auto有些不同,如果decltype使用的表达式是一个变量,则decltype返回该变量的类型(包括顶层const和引用在内)

const int ci = 0, &cj = ci;
decltype(ci) x = 0;   //x的类型是const int
decltype(cj) y = x;   //y的类型是const int& y绑定到变量x
decltype(cj) z;		  //错误 z是一个引用必须初始化

需要指出的是,引用从来都作为其所指对象的同义词出现,只有用在decltype处理是一个例外,decltype和引用:有些表达式将向decltype返回一个引用类型,代表着该表达式的结果对象能作为一条赋值语句的左值

//decltype的结果可以是引用类型
int i = 42, *p = &i, &r = i;
decltype(r + 0) b;    //正确 加法的结果是int,因此b是一个(未初始化的)int
decltype(*p) c;		  //错误 c是int&,必须初始化
decltype(p)  d;		  //正确 d是int*

因为r是一个引用,因此decltype(r)的结果是引用类型,如果想让结果类型是r所指的类型,则可以把r作为表达式的一部分,如r + 0,显然这个表达式的结果将是一个具体指而非一个引用,另一方面,如果表达式的内容是解引用操作,则decltype将得到引用类型,正如我们所熟悉的那样解引用指针可以得到指针所指的对象,而且还能给这个对象赋值,因此decltype(*p)的结果类型就是int&,而非int

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

decltype((i)) d;  //错误 d是int& 必须初始化
decltype(i) e;    //正确 e是一个(未初始化的)int

decltype与数组:还有一种情况,如果我们知道函数返回的指针将指向哪个数组,就可以使用decltype关键字声明返回类型
例如下面的函数返回一个指针,该指针根据参数i的不同指向俩个已知数组中的某一个

int odd[] = { 1,3,5,7,9 };
int even[] = { 0,2,4,6,8 };
//返回一个指针,该指针指向含有5个整数的数组
decltype(odd) *arrPtr(int i)
{
	return (i % 2) ? &odd : &even;  //返回一个指向数组的指针
}

decltype并不负责把数组类型转换成对应的指针,所以decltype的结果是个数组,要想表示arrPtr返回指针还必须在函数声明时加一个*符号

 

  • 尾置返回类型-->

任何函数的定义都能使用位置返回,但是这种形式对于返回类型比较复杂的函数最有效,比如返回类型是数组的指针或者数组的引用,尾置返回类型跟在形参列表后面并以一个->符号开头。为了表示函数真正的返回类型跟在形参列表之后,我们在本应该出现返回类型的地方放置一个auto

//func接受一个int类型的实参,返回一个指针,该指针指向含有10个整数的数组
auto func(int i)->int(*)[10];

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值