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

Why does double empty curly braces { { } } create a std::initializer_list<double> with one element, not zero?

我有以下构造函数:

MyItem(std::initializer_list<double> l) {
    std::cout << "l size " << l.size() << ")" << std::endl;
}

后面用双花括号调用:

MyItem{{}}

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

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

似乎嵌套的 {} 就像唯一元素的默认构造函数一样,但我不太明白为什么类型推导在这里起作用以及如何起作用。

当您使用大括号(list-initialization)初始化MyItem对象时,您显示的列表构造函数非常贪心。

这些将传递一个空列表:

MyItem foo({});
MyItem foo{std::initializer_list<double>{}};

这传递了一个包含单个元素的列表 - a value-initialized double (0.0):

MyItem foo{{}};

之所以可行,是因为在某些情况下您可以简单地使用大括号代替已知类型。在这里,它通过首选列表构造函数知道给定列表应包含 double.

为了完整起见,这看起来像是传递了一个空列表,但实际上 value-initializes foo 如果它有一个默认构造函数(或者在特殊情况下,做一些几乎相同的事情)。如果没有默认构造函数,它将选择列表构造函数,as shown here.

MyItem foo{};

这个表达式

MyItem{{}}

表示显式类型转换(函数符号)。

根据 C++ 标准(5.2.3 显式类型转换(函数符号))

  1. Similarly, a simple-type-specifier or typename-specifier followed by a braced-init-list creates a temporary object of the specified type direct-list-initialized (8.5.4) with the specified braced-init-list, and its value is that temporary object as a prvalue.

Class MyItem 有转换 initializer-list 构造函数

MyItem(std::initializer_list<double> l) {
    std::cout << "l size " << l.size() << ")" << std::endl;
}

选择显式类型转换。实际上相当于调用

MyItem( {{}} );

所以构造函数得到一个只有一个元素的初始化列表

{ {} }

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

结果,该表达式创建了一个 MyItem 类型的临时对象,该对象由一个初始化列表初始化,该列表包含一个双精度类型的元素,即 value-initialized 通过空大括号。