Читать «Эффективный и современный С++. 42 рекомендации по использованию С++11 и С++14» онлайн - страница 20
Скотт Мейерс
template<typename Т> // Объявление шаблона с параметром
void f(Т param); // эквивалентно объявлению x
f({ 11, 23, 9 }); // Ошибка вывода типа для Т
Однако, если вы укажете в шаблоне, что param
представляет собой std::initializer_list<T>
для некоторого неизвестного Т
, вывод типа шаблона сможет определить, чем является Т
:
template<typename Т>
void f(std::initializer_list<T> initList);
f({ 11, 23, 9 }); // Вывод int в качестве типа Т, а тип
// initList - std::initializer_list<int>
Таким образом, единственное реальное различие между выводом типа auto
и выводом типа шаблона заключается в том, что auto
std::initializer_list
, в то время как вывод типа шаблона этого не делает.
Вы можете удивиться, почему вывод типа auto
имеет специальное правило для инициализаторов в фигурных скобках, в то время как вывод типа шаблона такого правила не имеет. Но я и сам удивлен. Увы, я не в состоянии найти убедительное объяснение. Но “закон есть закон”, и это означает, что вы должны помнить, что если вы объявляете переменную с использованием ключевого слова auto
и инициализируете ее с помощью инициализатора в фигурных скобках, то выводимым типом всегда будет std::initializer_list
. Особенно важно иметь это в виду, если вы приверженец философии унифицированной инициализации — заключения инициализирующих значений в фигурные скобки как само собой разумеющегося стиля. Классической ошибкой в С++11 является случайное объявление переменной std::initializer_list
там, где вы намеревались объявить нечто иное. Эта ловушка является одной из причин, по которым некоторые разработчики используют фигурные скобки в инициализаторах только тогда, когда обязаны это делать. (Когда именно вы обязаны так поступать, мы рассмотрим в разделе 3.1.)
Что касается С++ 11, то на этом история заканчивается, но для С++14 это еще не конец. С++14 допускает применение auto
для указания того, что возвращаемый тип функции должен быть выведен (см. раздел 1.3), а кроме того, лямбда-выражения С++ 14 могут использовать auto
в объявлениях параметров. Однако такое применение auto
использует вывод типа шаблона, а не вывод типа auto
. Таким образом, функция с возвращаемым типом auto
, которая возвращает инициализатор в фигурных скобках, компилироваться не будет:
auto createInitList() {
return { 1, 2, 3 }; // Ошибка: невозможно вывести
} // тип для { 1, 2, 3 }
То же самое справедливо и тогда, когда auto
используется в спецификации типа параметра в лямбда-выражении С++14:
std::vector<int> v;
auto resetV =
[&v](const auto& newValue) { v = newValue; }; // C++14
resetV({ 1, 2, 3 }); // Ошибка: невозможно вывести
// тип для { 1, 2, 3 }
Следует запомнить
• Вывод типа auto
обычно такой же, как и вывод типа шаблона, но вывод типа auto
, в отличие от вывода типа шаблона, предполагает, что инициализатор в фигурных скобках представляет std::initializer_list
.
• auto
в возвращаемом типе функции или параметре лямбда-выражения влечет применение вывода типа шаблона, а не вывода типа auto
.