C++统一初始化语法(列表初始化)

软件发布|下载排行|最新软件

当前位置:首页IT学院IT技术

C++统一初始化语法(列表初始化)

jerry_fuyi   2020-04-30 我要评论
### 引言 要是世上不曾存在C++14和C++17该有多好!`constexpr`是好东西,但是让编译器开发者痛不欲生;新标准库的确好用,但改语法细节未必是明智之举,尤其是3年一次的频繁改动。C++带了太多历史包袱,我们都是为之买账的一员。 我没那么多精力考虑C++14/17的问题,所以本文基于C++11标准。 知其所以然,是学习C++越发复杂的语法的最佳方式。因此,我们从列表初始化的动机讲起。   ### 动机 早在2005年,Bjarne Stroustrup就提出要统一C++中的初始化语法。这是因为在C++11以前,初始化存在一系列问题,包括: - 4种初始化方式:`X t1 = v;`、`X t2(v);`、`X t3 = { v };`、`X t4 = X(v);`; - 聚合(aggregate)初始化; - `default`与`explicit`; - …… 虽然每一个都有办法解决,但加在一起将会变得非常复杂,对编译器和开发者都是负担。换句话说,唯一的需求就是一种**统一的初始化语法**,其适用范围能涵盖先前的各种问题。 于是,**列表初始化**诞生了。   ### 语法 正因为列表初始化是为解决初始化问题而生,列表初始化的适用范围是**任何初始化**。你能想到的都写写看,写对就是赚到。 当然,全凭感觉是行不通的,还是得讲点道理。列表初始化分为两类:直接初始化与拷贝初始化。 在直接初始化中,无论构造函数是否`explicit`,都有可能被调用: 1. `T object { arg1, arg2, ... };`,用`arg1, arg2, ...`构造`T`类型的对象`object`——参数可以是一个值,也可以是一个初始化列表,下同; 2. `Class { T member { arg1, arg2, ... }; };`,构造`member`成员对象——花括号的优势在这里体现出来,因为如果是圆括号的话`member`会被看作一个函数; 3. `T { arg1, arg2, ... }`,构造临时对象; 4. `new T { arg1, arg2, ... }`,构造heap上的对象; 5. `Class::Class() : member{arg1, arg2, ...} {...`,成员初始化列表——除了2以外,其余都与用`()`初始化没有区别。 在拷贝初始化中,无论构造函数是否`explicit`都会被考虑,但是如果重载决议为一个**`explicit`函数**,则此调用错误: 1. `T object = {arg1, arg2, ...};`,与直接初始化中的`1`类似,除了`explicit`以外都相同,`operator=`不会被调用; 2. `object = { arg1, arg2, ... }`,赋值语句,调用`operator=`; 3. `Class { T member = { arg1, arg2, ... }; };`,与直接初始化中的`2`类似,`explicit`同理; 4. `function( { arg1, arg2, ... } )`,构造函数参数; 5. `return { arg1, arg2, ... } ;`,构造返回值; 6. `object[ { arg1, arg2, ... } ]`,构造`operator[]`的参数; 7. `U( { arg1, arg2, ... } )`,构造`U`构造函数的参数。 4~7可以概括为,在该有一个对象的地方,可以用一个列表来构造它。这句话不是很严谨,因为除了`operator()`和`operator[]`以外,其他运算符的参数都不能用列表初始化。 还有一个要注意的地方,是列表初始化**不允许窄化转换**(narrowing conversion),即可能丢失信息的转换,如`float`转换为`int`。 ``` #include

Copyright 2022 版权所有 软件发布 访问手机版

声明:所有软件和文章来自软件开发商或者作者 如有异议 请与本站联系 联系我们