为什么auto x {3}推导出initializer_list?

Tri*_*dle 56 c++ initializer-list auto c++11 type-deduction

我喜欢autoC++ 11.太棒了.但它有一个不一致,真的让我紧张,因为我一直绊倒它:

int i = 3;       // i is an int with value 3
int i = int{3};  // i is an int with value 3
int i(3);        // i is an int with value 3 (possibly narrowing, not in this case)
int i{3};        // i is an int with value 3

auto i = 3;      // i is an int with value 3
auto i = int{3}; // i is an int with value 3
auto i(3);       // i is an int with value 3
auto i{3};       // wtf, i is a std::initializer_list<int>?!
Run Code Online (Sandbox Code Playgroud)

这种奇怪的行为让新手感到困惑,并且对有经验的用户来说很烦人--C++有足够的不一致性和角落案例,人们必须牢记这一点.任何人都可以解释为什么标准委员会决定在这种情况下引入一个新的?

我可以理解,如果声明一个类型的变量std::initializer_list是有用的或经常做的事情,但根据我的经验,它几乎从不故意 - 并且在极少数情况下,你确实想要这样做,任何

std::initializer_list<int> l{3};
auto l = std::initializer_list<int>{3};
auto l = {3}; // No need to specify the type
Run Code Online (Sandbox Code Playgroud)

会工作得很好.那特殊情况背后的原因是auto x{i}什么?

vax*_*uis 41

长话短说:

  • 支撑的初始化表达式{}本身没有类型
  • auto 必须推断类型信息
  • int{3}显然意味着"创建一个int从初始化列表中获取值的var",因此它的类型只是int可以在任何更广泛的上下文中使用(int i = int{3}将起作用并且auto i = int{3}可以推断类型,因为右侧显然是类型int)
  • {3}本身没有类型(它不能int的,因为它不是一个值,而是一个初始化列表),这样auto是行不通的-但是,因为委员会认为auto还是应该在这种情况下工作,他们决定,"最好"的类型for(是的,按照定义无类型)初始化列表将是...... std::initializer_list,正如您已经猜到的那样.

但是,正如您所指出的,这使得整个行为在auto语义上非常不一致.这就是为什么有提议改变它 - 即N3681,N3912N3922--提交给委员会的原因.由于没有委员会就此问题达成共识,之前的提案被拒绝为FI3,http://isocpp.org/files/papers/n3852.html#FI3,current(N3922)被采纳为 ca. 2015年第一季度 ;

tl;博士你可以假设符合标准的编译器1具有最前沿的C++支持2或者已经有了新的,更加理智的语义,或者很快就会有它.

标准化委员会通过将N3922纳入C++草案17来承认这一问题.

- 所以这是

auto x1 = { 1, 2 }; // decltype(x1) is std::initializer_list<int>
auto x2 = { 1, 2.0 }; // error: cannot deduce element type
auto x3{ 1, 2 }; // error: not a single element
auto x4 = { 3 }; // decltype(x4) is std::initializer_list<int>
auto x5{ 3 }; // decltype(x5) is int
Run Code Online (Sandbox Code Playgroud)

现在,无论好坏.

进一步阅读:

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3681.html

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n3912.html

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n3922.html

http://scottmeyers.blogspot.com/2014/03/if-braced-initializers-have-no-type-why.html

http://herbsutter.com/2014/11/24/updates-to-my-trip-report/


1 GCC 5.1(及以上)即使在C++ 11/C++ 14模式下也显然使用N3922

2 Clang 3.8,有警告

这是一个向后不兼容的更改,适用于所有允许从auto类型扣除的语言版本(根据C++委员会的请求).

  • N3922于一年多前(2014年11月,在Urbana)被采用. (3认同)
  • @ArneVogel我想是的.答案引用了Clang的明确警告,即该更改是向后兼容的并且适用于*所有语言版本*. (2认同)