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}
の特別なケースの背後にある理由は何ですか?
長い話を短くするには:
{}
自体には型がありませんauto
は型情報を推測する必要がありますint{3}
は明らかに「初期化リストから取得した値でint
varを作成する」ことを意味します。したがって、その型はint
であり、より広いコンテキストで使用できます(int i = int{3}
は機能し、auto i = int{3}
は型を推定できます。右側が明らかにint
であるためです){3}
自体にはタイプがありません(それはca n't be int
です。これはvalueではなくイニシャライザリスト)、つまりauto
は機能しません—ただし、委員会はauto
がこの場合でも機能するはずであると考えたため、「最良の」と判断しました(ええ、定義によりタイプレスです)初期化リストのタイプは... std::initializer_list
、おそらくご想像のとおり。しかし、ご指摘のとおり、これによりauto
の動作全体が意味的に一貫しなくなりました。それが、委員会に提出された、つまりN3681、N3912およびN3922を変更する提案があった理由です。この問題に関する委員会の合意がないため、以前の提案はFI3として却下されました http://isocpp.org/files/papers/n3852.html#FI 、現在(N3922 )取得 採用 2015年の第1四半期 ;
tl; dr標準準拠コンパイラ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/
1GCC 5.1(およびそれ以上) C++ 11/C++ 14モードでもN3922を使用しているようです
2Clang 3.8、警告付き
これは下位互換性のない変更であり、(C++委員会の要求に従って)autoからの型の推定を許可するすべての言語バージョンに適用されます。