Cpp 对象的初始化由构造函数控制,既然有 () 去调用构造函数,为什么还要有 {} 初始化呢?

2018-09-20 22:13:25 +08:00
 leebs

对于 initiailzer_list,Cpp 为什么只提供默认构造函数:cppreference
那我来初始化一下 vector:

vector<int> vec(initializer_list<int>());  // "expression must have class type" warning when using vec

为啥又不行呢?
为什么改成 {} 就可以了呢?

vector<int> vec(initializer_list<int>{}); // OK

{} 是脱离于构造函数之外的嘛?
那为什么用 {} 初始化有时候也必会调用对应的构造函数呢?

struct A{
    A(int a, int b){this->a = 2*a; this->b = 2*b;}

    int a;
    int b;
};

A a{1, 2}; // (2, 4)

brace(list) initialization 的设计到底是为了什么?

2574 次点击
所在节点    C
9 条回复
AngelCriss
2018-09-20 22:26:18 +08:00
看了几遍都没看明白你在说啥。。
HHehr0ow
2018-09-20 22:30:57 +08:00
most vexing parse 了解一下
v2byy
2018-09-20 22:51:55 +08:00
大括号初始化是 cpp11 引入的统一化初始化方式。具体建议你看下 effective modern cpp
innoink
2018-09-20 23:08:00 +08:00
initializer_list<int>()
被解析成了一个函数
你放个 int()也是一样
老问题了
innoink
2018-09-20 23:09:20 +08:00
被解析成了函数声明
chengluyu
2018-09-20 23:10:51 +08:00
Type variable();

上面的代码究竟是初始化了 variable 还是声明了一个叫 variable 的函数?

想想这个问题你就明白了。
innoink
2018-09-20 23:44:44 +08:00
如果你用过 tsd::function,就会知道类似于 int(char)这种是函数类型
因此 initializer_list<int>() 被解析成了类型名,即一个参数为空,返回值为 initializer_list<int>的函数类型
vector<int> vec(initializer_list<int>()); 则被解析成了一个 返回值为 vector<int>、参数为上一行的函数类型 的一个函数声明

你可以试着跑一下这个程序:
#include <iostream>
#include <vector>
#include <string>
int f()
{
std::cout << "111";
return 0;
}
std::vector<int> v(int())
{
std::cout << "222";
std::vector<int> x;
return x;
}

int main()
{
v(f);
return 0;

}
gnaggnoyil
2018-09-21 00:54:12 +08:00
>那为什么用 {} 初始化有时候也必会调用对应的构造函数呢?
对于非 aggragate,并且具有非默认构造函数的类型,list initialization 本来就会调用它们的(隐式)构造函数.
>brace(list) initialization 的设计到底是为了什么?
1.避免 most vexing parse.
2.它为 aggragate(以及数组)和非 aggragate 类型提供了统一的并且有实际作用的初始化 syntax,因为 aggragate 类型所拥有的构造函数只有隐式生成的那几个,没法用来初始化其所拥有的成员变量;而至于数组则连隐式生成的构造函数都没有.在写泛型代码或者修改类的定义的时候这种统一性会特别好使.事实上如果我没记错的话 C++标准中第二个能用于初始化一个 aggragate 类型对象的成员变量的语言特性还是 C++2a 中新加入的 designated initializers.
3.标准中明确禁止 list initialization 在参数匹配的时候基本类型的参数出现产生精度损失的 narrowing conversion,可以帮助避免很多 bug.
4.花括号列表中的表达式其可观察行为一定是表现的好像是从左到右被依次执行的,或者更准确的说,处于列表较后面的表达式一定 sequenced after 较前面的表达式.这个特性配合 pack expansion 可以简化很多变长模板的写法.
dangyuluo
2018-09-21 02:02:44 +08:00
读一下 Effective Modern C++,Item14 还是 17 来着,很详细。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/491339

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX