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



и >i. Если бы возвращаемый тип, как обычно, предшествовал имени функции, >c и >i были бы в нем недоступны, поскольку в этот момент они еще не были объявлены.

При таком объявлении >authAndAccess возвращает тот тип, который возвращает >operator[] при применении к переданному контейнеру, в точности как мы и хотели.

С++11 разрешает вывод возвращаемых типов лямбда-выражений из одной инструкции, а С++14 расширяет эту возможность на все лямбда-выражения и все функции, включая состоящие из множества инструкций. В случае >authAndAccess это означает, что в С++ 14 мы можем опустить завершающий возвращаемый тип, оставляя только одно ведущее ключевое слово >auto. При таком объявлении >auto означает, что имеет место вывод типа. В частности, это означает, что компиляторы будут выводить возвращаемый тип функции из ее реализации:

>template // С++14;

>auto authAndAccess(Container& с, Index i)    // Не совсем

>{                                            // корректно

> authenticateUser();

> return c[i];       // возвращаемый тип выводится из c[i]

>}

В разделе 1.2 поясняется, что для функций с >auto-спецификацией возвращаемого типа компиляторы применяют вывод типа шаблона. В данном случае это оказывается проблематичным. Как уже говорилось, >operator[] для большинства контейнеров с объектами типа возвращает >Т&, но в разделе 1.1 поясняется, что в процессе вывода типа шаблона “ссылочность” инициализирующего выражения игнорируется. Рассмотрим, что это означает для следующего клиентского кода:

>std::deque d;

>…

>authAndAccess(d, 5) = 10; // Аутентифицирует пользователя, воз-

>                          // вращает d[5], затем присваивает ему

>                          // значение 10. Код не компилируется!

Здесь >d[5] возвращает >int&, но вывод возвращаемого типа >auto для >authAndAccess отбрасывает ссылку, тем самым давая возвращаемый тип >int. Этот >int, будучи возвращаемым значением функции, является >rvalue, так что приведенный выше код пытается присвоить этому >rvalue типа int значение 10. Это запрещено в С++, так что данный код не компилируется.

Чтобы заставить >authAndAccess работать так, как мы хотим, нам надо использовать для ее возвращаемого типа вывод типа >decltype, т.е. указать, что >authAndAccess должна возвращать в точности тот же тип, что и выражение >с[i]. Защитники С++, предвидя необходимость использования в некоторых случаях правил вывода типа >decltype, сделали это возможным в С++14 с помощью спецификатора