Эффективный и современный С++. 42 рекомендации по использованию С++11 и С++14 | страница 22
> // uref3 - int&&
Раздел 1.1 завершился обсуждением того, как имена массивов и функций превращаются в указатели для спецификаторов типа, не являющихся ссылками. То же самое происходит и при выводе типа >auto
:
>const char name[] = // Тип name - const char [13]
> "R. N. Briggs";
>auto arr1 = name; // Тип arr1 - const char*
>auto& arr2 = name; // Тип arr2 - const char (&)[13]
>void someFunc(int, double); // someFunc - функция, ее тип
> // void(int, double)
>auto func1 = someFunc; // Тип func1 - void (*)(int, double)
>auto& func2 = someFunc; // Тип func2 - void (&)(int, double)
Как можно видеть, вывод типа >auto
работает подобно выводу типа шаблона. По сути это две стороны одной медали.
Они отличаются только в одном. Начнем с наблюдения, что если вы хотите объявить >int
с начальным значением 27, С++98 предоставляет вам две синтаксические возможности:
>int x1 = 27;
>int x2(27);
С++11, поддерживая старые варианты инициализации, добавляет собственные:
>int x3 = { 27 };
>int x4{ 27 };
Таким образом, у нас есть четыре разных синтаксиса, но результат один: переменная типа >int
со значением 27.
Но, как поясняется в разделе 2.1, объявление переменных с использованием ключевого слова >auto
вместо фиксированных типов обладает определенными преимуществами, поэтому в приведенных выше объявлениях имеет смысл заменить >int
на >auto
. Простая замена текста приводит к следующему коду:
>auto x1 = 27;
>auto x2(27);
>auto x3 = { 27 };
>auto x4{ 27 };
Все эти объявления компилируются, но их смысл оказывается не тем же, что и у объявлений, которые они заменяют. Первые две инструкции в действительности объявляют переменную типа >int
со значением 27. Вторые две, однако, определяют переменную типа >std::initializer_list
, содержащую единственный элемент со значением 27!
>auto x1 = 27; // Тип int, значение - 27
>auto x2(27); // То же самое
>auto x3 = { 27 }; // std::initializer_list
>auto x4{ 27 }; // То же самое
Это объясняется специальным правилом вывода типа для >auto
. Когда инициализатор для переменной, объявленной как >auto
, заключен в фигурные скобки, выведенный тип — >std::initializer_list
. Если такой тип не может быть выведен (например, из-за того, что значения в фигурных скобках относятся к разным типам), код будет отвергнут:
>auto x5 = { 1, 2, 3.0 }; // Ошибка! Невозможно вывести Т
> // для std::initializer_list