Эффективный и современный С++. 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, значение (27}

>auto x4{ 27 };    // То же самое

Это объясняется специальным правилом вывода типа для >auto. Когда инициализатор для переменной, объявленной как >auto, заключен в фигурные скобки, выведенный тип — >std::initializer_list. Если такой тип не может быть выведен (например, из-за того, что значения в фигурных скобках относятся к разным типам), код будет отвергнут:

>auto x5 = { 1, 2, 3.0 }; // Ошибка! Невозможно вывести Т

>                         // для std::initializer_list