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

时间:2014-09-01 19:57:49

标签: c++ c++11 auto initializer-list type-deduction

我喜欢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_list类型的变量是有用的或经常做的事情,我能理解它,但根据我的经验,它几乎从不是故意的 - 在极少数情况下你确实想要

中的任何一个
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}特殊情况背后的原因是什么呢?

1 个答案:

答案 0 :(得分:40)

长话短说:

  • 支持的初始化表达式{}本身没有类型
  • auto必须推断类型信息
  • int{3}显然意味着&#34;创建一个int var,其值取自初始化列表&#34;,因此其类型只是int,可以在任何更广泛的上下文中使用(int i = int{3}可以使用,auto i = int{3}可以推断出类型,因为右侧显然属于int类型
  • {3}本身没有类型(可以&#39; int,因为它不是但是初始化列表),因此auto无法正常工作 - 但是,由于委员会认为auto在这种情况下仍应有效,因此他们决定&# 34;最好的&#34;类型为(是的,无定义的)初始化列表将是...... std::initializer_list,正如您可能已经猜到的那样。

但是,正如您所指出的,这使得auto的整个行为在语义上非常不一致。这就是提出改变建议的原因 - 即 N3681 N3912 N3922 - 提交给委员会。由于没有委员会就此问题达成共识,前提案被拒绝为FI3,http://isocpp.org/files/papers/n3852.html#FI3,当前( N3922 )得到adopted ca. Q1 of 2015;

tl; dr 你可以假设standards-compliant compilers1 bleeding-edge C++ support2http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3681.html已经有了新的,更健全的语义,或者很快就会有。

  

标准化委员会通过将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/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/

apparently uses N3922 even in C++11/C++14 mode


1 GCC 5.1(&amp; up){{3}}

2 Clang 3.8,注意事项

  

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