文 / 李博(光宇广贞)
本篇实验平台信息请见《这篇文章》。
在《C++ 0x 新标准全部革新提案文档列表》中,N1478 N1527 N1607 N1705 N1978 N2115 N2343 等文件提案向新标准语言内核中添加 decltype 算符和 auto 关键字(旧体新义)。该提案由 BS 参与设计。decltype 算符用于查询表达式类型;auto 关键字修饰变量声明,指示编译器根据变量的初始化表达式推导变量应有的类型。
Auto
关于 auto 关键字的用法定义很明确,也没什么花样。首先是定义变量,这里 auto 其需求、其存在价值、其意义、其用法,和 C# 下的 var 关键字一模儿一样。和 var 一样,auto 声明的变量必须“在声明处完成初始化”,编译器才可根据初始化表达式推导变量的类型。无论 auto 还是 var,都算是强类型与易用性之间的妥协罢。
不过 C++ 下的 auto 比 C# 下的 var 要麻烦一些。因为 C++ 把“指针、引用、值”在语义上分得太清楚了。所以在使用上,会带来一些困惑,或者用当下流行的词儿,叫“纠结”……比如如下用法:
在此,var1 和 var2 都会被推导为 int* 型。不过“引用”就另说了,比如如下用法:
在此,refInt 是 int& 型,而 var3 是 int 型,var4 是 int& 型。我对此的解释是,尽管编译器对“引用”与“指针”的处理方式相同,但是语义上二者相差甚远。“指针”是表示地址的“值”,而“引用”是“值”的别号。不管 refInt 是否引用,处在等号右边,待之以右值,得到的便是其实体(entity type)——若是值,则是值本身;若是引用,则为引用所引之值。所以,auto 只会推导出等号右边的“右值”的实体类型,若需声明为引用,则须显式声明为 auto&。而对 var1 和 var2 来说,都会正确推导出“指针值”类型,var 2 的 auto 后面的 * 就被编译器忽略了。
噢,对了,还有一个 const,比如如下用法:
在此,intConst 是 const int 型。var5 为 int 型,var6 为 const int& 型,var7 为 const int 型。很奇怪呵。同理,编译器将只会推导出“右值”的实体类型,也就是 int,那么 var5 和 var7 都好解释了。而 var6 声明为引用,引用的是等号右边的“右值”,既是引用,编译器就会确认引用的是 const int 类型,因故 var6 为 const int& 型。显然 var6 做为引用与要引用的“右值”有关,而 var5 和 var7 和“右值”没有关系。
注意一:auto 不能做为模板参数。因为这违背了 auto 需要由初始化表达式来推导类型的原则。尽管 BS 一开始设计的时候认为这种用法应该被允许,但是 VS 2010 给以了拒绝。话又说回来了,如下所示,与其写成第一个句子,为何不直接写成第二个的样子呢?
显然,第二个句子才能体现 auto 的意义和存在价值。
注意二:auto 不能做为函数的参数类型和返回类型。同样是因为违背了 auto 推导类型的原则。函数在编译时要实例化,此时便需要确定参数的类型,以方便安排内存。声明为 auto 的话如何确定其类型呢?没法确定,所以这样用是不允许的。再说了,如果参数表可以 auto 的话,那倒是比重载函数还要强大了……返回类型更不可以 auto,函数返回值是“右值”,“右值”要提供类型说明的,不可以 auto。
除了在变量声明处用以声明变量之外,auto 还可以引导一种函数定义式,名为 forwarding function。由于网络翻译混乱,本文对此干脆提出一个自定义的比较“给劲”的叫法——“前导函数”。这个放到 decltype 的介绍中说。
好像还有件事儿没有交待,auto 关键字原来就有,也用来声明变量,但原先是用来声明“可变局部变量”的,和 static const 关键字相对。问题是,哪个非 static const 的变量不是 auto 的呢?我声明个整型局部变量用 int i 就可以了,几乎没有人写成“规范”的 auto int i 吧。于是,做为 C / C++ 语言中最废的关键字,auto 旧词在新标准中被赋予新义,获得了新生——当然旧生就死了,VS 2010 中再这么写 auto int i 的话会编译报错(注:但是 IDE 不做提示,不能不说 BETA1 版的 VS 2010 挺让人别扭的,同样存在问题的还有右值引用 &&)。
Decltype
decltype 就是 declared type 的缩写。先摆出 decltype 的语义三规则(N2343):
The type denoted by decltype ( e ) is defined as follows:
- If e is an id-expression or a class member access, decltype ( e ) is defined as the type of the entity named by e. If there is no such entity, or e names a set of overloaded functions, the program is ill-formed.
- If e is a function call or an invocation of an overloaded operator ( parentheses around e are ignored ), decltype ( e ) is defined as the return type of that funcion.
- Otherwise, where T is the type of e, if e is an lvalue, decltype ( e ) is defined as T&, otherwise http://msnpiki.msnfanatic.com/index.php/Main_Page-->
验证码:
注册会员 会员登陆