Эффективный и современный С++. 42 рекомендации по использованию С++11 и С++14 - страница 14

стр.

Они отличаются только в одном. Начнем с наблюдения, что если вы хотите объявить >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

Как указано в комментарии, в этом случае вывод типа будет неудачным, но важно понимать, что на самом деле здесь имеют место два вывода типа. Один из них вытекает из применения ключевого слова >auto: тип >x5 должен быть выведен. Поскольку инициализатор >x5 находится в фигурных скобках, тип >x5 должен быть выведен как >std::initializer_list. Но >std::initializer_list — это шаблон. Конкретизация представляет собой создание >std::initializer_list с некоторым типом , а это означает, что тип также должен быть выведен. Такой вывод относится ко второй разновидности вывода типов — выводу типа шаблона. В данном примере этот второй вывод неудачен, поскольку значения в фигурных скобках не относятся к одному и тому же типу.

Рассмотрение инициализаторов в фигурных скобках является единственным отличием вывода типа >auto от вывода типа шаблона. Когда объявленная с использованием ключевого слова >auto переменная инициализируется с помощью инициализатора в фигурных скобках, выведенный тип представляет собой конкретизацию >std::initializer_list. Но если тот же инициализатор передается шаблону, вывод типа оказывается неудачным, и код отвергается:

>auto x = { 11, 23, 9 }; // Тип x – std::initializer_list


>template    // Объявление шаблона с параметром

>void f(Т param);        // эквивалентно объявлению x


>f({ 11, 23, 9 });       // Ошибка вывода типа для Т

Однако, если вы укажете в шаблоне, что >param представляет собой >std::initializer_list для некоторого неизвестного , вывод типа шаблона сможет определить, чем является :

>template

>void f(std::initializer_list<T> initList);


>f({ 11, 23, 9 }); // Вывод int в качестве типа Т, а тип

>                  // initList - std::initializer_list

Таким образом, единственное реальное различие между выводом типа >auto и выводом типа шаблона заключается в том, что >autoпредполагает, что инициализатор в фигурных скобках представляет собой >std::initializer_list, в то время как вывод типа шаблона этого не делает.

Вы можете удивиться, почему вывод типа >auto имеет специальное правило для инициализаторов в фигурных скобках, в то время как вывод типа шаблона такого правила не имеет. Но я и сам удивлен. Увы, я не в состоянии найти убедительное объяснение. Но “закон есть закон”, и это означает, что вы должны помнить, что если вы объявляете переменную с использованием ключевого слова