Почему auto x{3} выводит список инициализаторов?


Я люблю auto в C++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>?!

это странное поведение сбивает с толку новичков и раздражает опытных пользователей-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   51   2014-09-01 23:57:48

1 ответ:

чтобы сделать длинную историю короткой:

  • связанное выражение инициализатора {} не имеет типа сам по себе
  • auto должен вывести информацию типа
  • int{3} очевидно, означает "создать int var со значением, взятым из списка инициализаторов", таким образом, его тип просто int и может использоваться в любом более широком контексте (int i = int{3} совместимость и auto i = int{3} может вывести тип, потому что правая сторона, очевидно, типа int)
  • {3} by сам по себе не имеет типа (это не могу быть int, потому что это не стоимостью но список инициализатора), так auto не сработало бы-но, потому что комитет рассмотрел это auto по-прежнему должны работать в этом случае, они решили, что "лучшие" типа (да, типизации по определению) список инициализатора будет... std::initializer_list, как вы уже наверное догадались.

но, как вы указали, это сделало все поведение auto вполне семантически несовместимы. Поэтому и были предложения его изменить-а именно N3681, N3912 и N3922 - представляется в комитет. Прежнее предложение было отклонено как FI3 из - за отсутствия консенсуса комитета по этому вопросу, http://isocpp.org/files/papers/n3852.html#FI3, current ( N3922) у принят ca. 1 квартал 2015 года;

tl; dr вы можете предположить, что совместимые со стандартами компиляторы1 с bleeding-edge c++ support2 либо у вас уже есть новая, более здравая семантика, либо она будет скоро.

Комитет по стандартизации признал эту проблему, приняв 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 (&up) по-видимому, использует N3922 даже в режиме C++11/C++14

2лязг 3.8, с оговоркой

это обратно несовместимое изменение, которое применяется ко всем языковым версиям, которые позволяют вычесть тип из auto (по запросу Комитета C++).