为什么双空花括号{{}}用一个元素创建一个std :: initializer_list <double>,而不是零?

Nik*_*nov 18 c++ initializer-list

我有以下构造函数:

MyItem(std::initializer_list<double> l) {
    std::cout << "l size " << l.size() << ")" << std::endl;
}
Run Code Online (Sandbox Code Playgroud)

以后用双花括号调用:

MyItem{{}}
Run Code Online (Sandbox Code Playgroud)

结果l.size()给出的是1.

这种行为背后的机制是什么?

似乎嵌套的{}扮演的是唯一元素的默认构造函数,但我不太明白为什么以及类型推导在这里如何工作.

chr*_*ris 10

当您使用大括号(列表初始化)来初始化MyItem对象时,您显示的列表构造函数非常贪婪.

这些将传递一个空列表:

MyItem foo({});
MyItem foo{std::initializer_list<double>{}};
Run Code Online (Sandbox Code Playgroud)

这会传递一个包含单个元素的列表 - 值初始化double(0.0):

MyItem foo{{}};
Run Code Online (Sandbox Code Playgroud)

这是有效的,因为在某些情况下,您可以简单地使用大括号代替已知类型.在这里,它知道从列表构造函数中选择给定列表应该包含的内容double.

为了完整性,这看起来像是传递一个空列表,但foo如果它有一个默认的构造函数,它实际上是值初始化(或者在特殊情况下,它做了几乎相同的事情).如果没有默认构造函数,它将选择列表构造函数,如下所示.

MyItem foo{};
Run Code Online (Sandbox Code Playgroud)

  • 回到问题的例子,更明显的是看到为什么`foo({});`知道从大括号中创建一个`字符串` - 它只有一种类型!以同样的方式,有一条规则说`MyItem foo {{}};`调用将从元素(这里只是内部`{}`)创建一个`initializer_list <double>`,如果可能的话.还有另一个规则是说要从`{}`创建一个`double`,你得到的值为0.0.将这些放在一起你可以看到可以创建一个`initializer_list <double>` - 一个元素,其中`{}`变成0.0. (2认同)

Vla*_*cow 5

这个表达

MyItem{{}}
Run Code Online (Sandbox Code Playgroud)

表示显式类型转换(功能表示法).

根据C++标准(5.2.3显式类型转换(功能表示法))

  1. 类似地,一个simple-type-specifier或typename-specifier后跟一个braced-init-list,用指定的braced-init-list创建一个指定类型direct-list-initialized(8.5.4)的临时对象及其值是临时对象作为prvalue.

类MyItem具有转换初始化列表构造函数

MyItem(std::initializer_list<double> l) {
    std::cout << "l size " << l.size() << ")" << std::endl;
}
Run Code Online (Sandbox Code Playgroud)

为显式类型转换选择的.实际上它等同于通话

MyItem( {{}} );
Run Code Online (Sandbox Code Playgroud)

因此构造函数获取具有一个元素的初始化列表

{ {} }
Run Code Online (Sandbox Code Playgroud)

可以使用空括号初始化double类型的标量对象{}.

结果表达式创建了一个类型的临时对象,MyItem该对象由初始化列表初始化,该列表包含一个double类型的元素,该元素通过空括号进行值初始化.