C++语言之C++ 11 新特性之类型推断与类型获取
小职 2018-03-07 来源 :网络 阅读 1460 评论 0

摘要:本篇C++语言教程将为大家讲解C++语言编程的知识点,看完这篇文章会让你对C++语言编程的知识点有更加清晰的理解和运用。

本篇C++语言教程将为大家讲解C++语言编程的知识点,看完这篇文章会让你对C++语言编程的知识点有更加清晰的理解和运用。

是C++11新特性介绍的第二部分,涉及到C++11这次更新中较为重要的特性类型推断(auto)与类型获取(decltype)。

不想看toy code的读者可以直接拉到文章最后看这部分的总结。

简单的类型推断

C++11新标准中增加了auto类型说明符,可以让编译器帮我们分析表达式的类型。

double val1 = 1.1, val2 = 2.2;auto sum = val1 + val2;auto val3 = 0.3, *p = &val3;//auto val4 = 0, val5 = 0.0; // wrong. different types.//auto sum2; // wrong, auto type must be initialized.double val6 = 1.6, &rval6 = val6;auto aval6 = rval6;

aval6 = 6.0; // aval6 is not a reference.

cout<<"test simple auto:\n"<<val1<<'\t'<<val2<<'\t'<<sum<<'\t'<<val3<<'\t'<<p<<'\t'<<val6<<'\t'<<rval6<<'\t'<<aval6<<endl;

需要注意的是

1.使用auto定义的变量必须有初始值,不然无法进行类型推断
2.在同一条语句中使用auto定义的变量,其基础类型必须一致

const和auto

auto在进行类型推断时,一般会忽略顶层const(top-level const),而保留底层const(low-level const)。如果想要保留顶层const,则必须显式的在auto前添加const指示符。

所谓顶层const,指的是当前的数据类型本身是常量,如double,int或者相关的指针本身是常量;

而底层const,指的是如指针、引用等复合类型,其所指向的数据类型是常量。

const int val7 = 1, &rval7 = val7;auto aval7 = val7; // remove top-level const

aval7 = 7;auto aval8 = rval7; // remove top-level const

aval8 = 8;auto aval9 = &val6; // not const

*aval9 = 9;auto aval10 = &val7; // keep low-level const//*aval10 = 10; // wrong. const int can't be changed.const auto aval11 = val7; // top-level const auto//aval11 = 11; // wrong. const int can't be changed.auto &aval12 = val7; // keep top-level const//aval12 = 12; // wrong. const referenceauto &aval13 = val6;

aval13 = 13.0;//auto &aval14 = 42; // wrong. must be const autoconst auto &aval15 = 15;//aval15 = 16; // wrong. const reference.//auto &aval16 = aval7, *aval17 = &val7; // wrong. type not consistentcout<<"test auto and const:\n"<<val7<<'\t'<<rval7<<'\t'<<aval7<<'\t'<<aval8<<'\t'<<*aval9<<'\t'<<aval10<<'\t'<<aval11<<'\t'<<aval12<<'\t'<<aval13<<'\t'<<aval15<<endl;

当定义一个auto的引用时,顶层const被保留,如上述测试代码中的aval12所示。另外,输出的结果中,有些数值可能和预想的不太一样,可以思考一下是为什么^_^(Tips: 和引用有关)。

类型获取decltype

decltype(expr)可以获得expr表达式对应的类型,并且不会对expr具体求值。

int d(){

cout<<"This function shouldn't be called."<<endl;

return 17;

}decltype(d()) dval17 = 15.2;cout<<"test decltype:\n"<<dval17<<endl;

decltype与const

decltype处理const的方式与auto不同。

1.如果decltype中的表达式是一个变量,那么返回该变量的类型(包括顶层const)
2.如果decltype中的表达式不是变量,则返回该表达式结果对应的类型。

看上去没啥区别?其实这里的规则导致了decltype(r+0) decltype((i))这种诡异的写法。还是具体看代码吧。

decltype(val7) val18 = 0;decltype(rval7) val19 = val18;//val19 = 10; // wrong. val19 is a reference to const int.cout<<"test decltype and const:\n"<<val18<<'\t'<<val19<<endl;

//double *pval20 = &val6;//decltype(*pval20) val21; // wrong. decltype(*pval20) = double&, must be initialized.decltype(rval6 + 0) val22;//decltype((val6)) val23; //wrong. decltype((val6)) == double&, must be initialized.decltype(val6) val24;cout<<"test decltype and reference:\n"<<val22<<'\t'<<val24<<endl;

上面代码中需要注意的地方有:

1.val21处,如果decltype中的表达式是一个解引用操作,那么将得到一个引用类型,所以必须初始化。
2.val22处,rval6是一个引用类型(double&),如果我们需要获得这个引用的基础类型(即double),那么使用rval6 + 0这样一个表达式,显然这个表达式的结果将不是引用了。
3.val23和val24处,如果decltype中的变量加上了括号,那么就会被当作表达式处理;而变量是一种可以作为左值被赋值的特殊表达式,因此decltype对于这种带括号的变量(val23处),就会得到一个引用类型。

使用auto缩写类型

string name = "Yubo";auto length = name.size();cout<<"test auto with complex type:\n"<<length<<endl;

不用费劲写string::size_type了^o^

使用auto简化声明

声明指向数组的指针总是一件令人痛苦的事情:

int val25[3][4] = {

{0, 1, 2, 3},

{4, 5, 6, 7},

{8, 9, 10, 11}

};cout<<"test auto to simplify type:\n";cout<<"old way:\n";for(int (*p)[4] = val25; p != val25 + 3; p++)

{

for(int *q = *p; q != *p + 4; q++)

{

cout<<*q<<'\t';

}

cout<<'\n';

}

有了auto之后,我们可以像下面这样清爽:

cout<<"new way:\n";for(auto ap = val25; ap != val25 + 3; ap++)

{

for(auto aq = *ap; aq != *ap + 4; aq++)

{

cout<<*aq<<'\t';

}

cout<<'\n';

}

使用decltype简化函数返回类型

如果我们已经知道某个函数会返回什么对象,然而这个对象又是一个类型复杂不好写的对象,那么decltype就可以派上用场了。

int odd[] = {1, 3, 5, 7, 9};int even[] = {0, 2, 4, 6, 8};decltype(odd) *get_odd_or_even(int i)

{

return (i % 2) ? &odd : &even;

}auto val26 = get_odd_or_even(1);cout<<"test decltype to simplify func return type:\n";for(auto p = begin(*val26); p != end(*val26); p++)

{

cout<<p<<' '<<*p<<'\t';

}cout<<endl;

使用auto动态分配内存

auto可以和new配合,来动态分配内存,并进行初始化。

auto val27 = new auto(val24);auto val28 = new auto(name);cout<<"test auto to new object with a given obj:\n";cout<<*val27<<'\t'<<*val28<<'\t'<<val28<<'\t'<<&name<<endl;auto val29 = new auto(odd); // right. can use auto to new a pointer to an arrayfor(auto p = *val29; p != *val29 + 5; p++)

{

cout<<p<<' '<<*p<<'\t';

}cout<<endl;

//auto val30 = new auto[10](val24); // wrong. can't use auto to new an arrayint *val31 = new int[10]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; // this is rightcout<<val31<<'\t'<<val31[0]<<"to"<<val31[9]<<endl;

这里有几处需要留意的地方:

1.val29处,只是new出了一个指向数组的指针,并没有复制数组的值。因此在下面循环中打印出的p值(地址)和odd数组的地址是一样的。
2.不可以使用auto来分配一个动态数组。这是因为使用new分配数组时,不支持圆括号的初始化方式,只支持花括号的列表初始化方式。

总结

1. 可以使用auto说明符,让编译器帮我们推断类型。

2. auto在进行类型推断时,一般会忽略顶层const(top-level const),而保留底层const(low-level const)。

3. decltype(expr)可以获得expr表达式对应的类型,并且不会对expr具体求值。

4. decltype(rval + 0)可以获得值类型(非引用),decltype(*p)获得引用类型,decltype((val))获得引用类型。

5. 使用auto可以缩写一些复杂难写的类型。

6. 使用auto可以简化类型声明,尤其是数组和指针混合的声明。

7. 在知道某一函数会返回什么对象时,可以使用decltype可以简化函数返回类型。

8. auto和new可以配合以动态分配内存,但是不能用于动态分配数组。

完整代码详见 auto_decltype.cpp

 

以上,关于C++的全部内容讲解完毕啦,欢迎大家继续关注!更多关于C++的干货请关注职坐标C++频道!

本文由 @小职 发布于职坐标。未经许可,禁止转载。
喜欢 | 1 不喜欢 | 0
看完这篇文章有何感觉?已经有1人表态,100%的人喜欢 快给朋友分享吧~
评论(0)
后参与评论

您输入的评论内容中包含违禁敏感词

我知道了

助您圆梦职场 匹配合适岗位
验证码手机号,获得海同独家IT培训资料
选择就业方向:
人工智能物联网
大数据开发/分析
人工智能Python
Java全栈开发
WEB前端+H5

请输入正确的手机号码

请输入正确的验证码

获取验证码

您今天的短信下发次数太多了,明天再试试吧!

提交

我们会在第一时间安排职业规划师联系您!

您也可以联系我们的职业规划师咨询:

小职老师的微信号:z_zhizuobiao
小职老师的微信号:z_zhizuobiao

版权所有 职坐标-一站式IT培训就业服务领导者 沪ICP备13042190号-4
上海海同信息科技有限公司 Copyright ©2015 www.zhizuobiao.com,All Rights Reserved.
 沪公网安备 31011502005948号    

©2015 www.zhizuobiao.com All Rights Reserved

208小时内训课程