为什么auto x {3}会推导一个initializer_list?

我喜欢在C + + 11 auto 。 太棒了 但是它有一个矛盾让我很紧张,因为我一直在绊倒它:

 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>?! 

这种奇怪的行为让新手感到困惑,而且对于有经验的用户来说很烦人 – C ++有足够的小小的不一致性和一些必须牢记在心的情况。 任何人都可以解释为什么标准委员会决定在这种情况下推出一个新的?

我可以理解,如果声明std::initializer_listtypes的variables是有用的或经常做的事情,但根据我的经验,几乎从来没有故意 – 在极less数情况下,你确实想要这样做,任何

 std::initializer_list<int> l{3}; auto l = std::initializer_list<int>{3}; auto l = {3}; // No need to specify the type 

会工作得很好。 那么auto x{i}的特例背后的原因是什么?

长话短说:

  • 支撑初始化expression式{}本身没有types
  • auto必须推断types信息
  • int{3}明显的意思是“用初始化列表中的值创build一个int var”,因此它的types就是int ,可以在任何更广的上下文中使用( int i = int{3}将会工作并且auto i = int{3}可以推导出types,因为右边显然是inttypes的)
  • {3}本身没有types(它不能int ,因为它不是一个值,而是一个初始化列表 ),所以auto不起作用 – 但是,因为委员会认为auto应该仍然在这种情况下工作,他们决定(是,无定义)初始化器列表的“最佳”types将是… std::initializer_list ,你可能已经猜到了。

但是,正如你所指出的那样,这使auto的整个行为在语义上相当不一致。 这就是为什么要提交给委员会的build议,即N3681N3912N3922 。 由于该委员会没有达成共识,因此前提案被否决为FI3, http : //isocpp.org/files/papers/n3852.html#FI3 ,目前( N3922通过了 CA. 2015年第一季度 ;

你可能会认为符合标准的编译器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 

现在,好或坏。

进一步阅读:

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(&up) 显然在C ++ 11 / C ++ 14模式下使用N3922

2叮当3.8,与警告

这是一个向后不兼容的变化,适用于允许从auto(根据C ++委员会的要求)自动扣除types的所有语言版本。