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

стр.

и инициализируете ее с помощью инициализатора в фигурных скобках, то выводимым типом всегда будет >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 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.

1.3. Знакомство с >decltype

>decltype — создание странное. Для данного имени или выражения >decltype сообщает вам тип этого имени или выражения. Обычно то, что сообщает >decltype, — это именно то, что вы предсказываете. Однако иногда он дает результаты, которые заставляют вас чесать в затылке и обращаться к справочникам или сайтам.

Мы начнем с типичных случаев, в которых нет никаких подводных камней. В отличие от того, что происходит в процессе вывода типов для шаблонов и >auto (см. разделы 1.1 и 1.2), >decltype обычно попугайничает, возвращая точный тип имени или выражения, которое вы передаете ему:

>const int i = 0;         // decltype(i) - const int


>bool f(const Widget& w); // decltype(w) - const Widget&

>                         // decltype(f) - bool(const Widget&)


>struct Point {

> int x, y;               // decltype (Point::x) - int

>};                       // decltype(Point::y) – int


>Widget w;                // decltype(w) – Widget


>if (f(w)) …              // decltype (f(w)) — bool


>template     // Упрощенная версия std::vector

>class vector {

>public:

> …

> T& operator[](std::size_t index);

>};


>vector v;           // decltype(v) – vector

>…

>if (v[0] == 0) …                  >// decltype(v[0]) - int&

Видите? Никаких сюрпризов.

Пожалуй, основное применение >decltype в С++11 — объявление шаблонов функций, в которых возвращаемый тип функции зависит от типов ее параметров. Предположим, например, что мы хотим написать функцию, получающую контейнер, который поддерживает индексацию с помощью квадратных скобок (т.е. с использованием “>[]”) с индексом, а затем аутентифицирует пользователя перед тем как вернуть результат операции индексации. Возвращаемый тип функции должен быть тем же, что и тип, возвращаемый операцией индексации.

>operator[] для контейнера объектов типа обычно возвращает >Т&. Например, это так в случае >std::deque и почти всегда — в случае >std::vector. Однако для >std::vector оператор >operator[] не возвращает >bool&. Вместо этого он возвращает новый объект. Все “почему” и “как” данной ситуации рассматриваются в разделе 2.2, но главное здесь то, что возвращаемый оператором