为什么必须包含<initializer_list>才能使用auto?

MWi*_*Wid 5 c++ types initializer-list auto c++11

在SO上已经有类似的问题,但我想强调braced-init-lists的另一个方面.考虑以下:

auto x = {1}; //(1)
Run Code Online (Sandbox Code Playgroud)

除非<initializer_list>包含标题,否则这是不正确的(8.5.4/2).但为什么?标准说,模板std::initializer_list不是预定义的.这是否意味着,声明(1)引入了一种新类型?在所有其他情况下,auto可以使用的地方如

auto y = expr;
Run Code Online (Sandbox Code Playgroud)

where expr是表达式,auto deduces类型已经存在.另一方面,从逻辑的角度来看,编译器必须为构造分配一个implicite类型{1},std::initializer_list然后是另一个名称.但是在声明(1)中我们不想命名这种类型.那么为什么必须包括这个标题.有类似的情况nullptr.它的类型隐含存在,但要明确指出它必须包括<cstddef>.

Seb*_*edl 8

那不一样.规则std::nullptr_tstd::initializer_list实际上是不同的.

std::nullptr_t只是内置类型的typedef.它的定义是

namespace std {
  using nullptr_t = decltype(nullptr);
}
Run Code Online (Sandbox Code Playgroud)

无论您是否包含标题,都存在该类型.

std::initializer_list是一个类模板,而不是预定义的类型.除非您包含定义它的标头,否则它确实不存在.特别是,初始化列表{ 1 }没有类型std::initializer_list<int>; 它根本没有类型,因为它不是表达式.(初始化列表是特殊的语法结构,不能出现在表达式的任何地方.)

std::initializer_list只是有点特别.例如,如何std::initializer_list从初始化列表语法初始化a (分配数组并让对象引用它)有一些特殊规则.但是,这需要std::initializer_list首先定义.

第二个特例是auto类型扣除.这里也有一个特殊的规则.但同样,这并不意味着编译器会自动定义类型; 它只是意味着它会识别它.