Эффективный и современный С++. 42 рекомендации по использованию С++11 и С++14 | страница 26
>i
. Если бы возвращаемый тип, как обычно, предшествовал имени функции, >c
и >i
были бы в нем недоступны, поскольку в этот момент они еще не были объявлены.При таком объявлении >authAndAccess
возвращает тот тип, который возвращает >operator[]
при применении к переданному контейнеру, в точности как мы и хотели.
С++11 разрешает вывод возвращаемых типов лямбда-выражений из одной инструкции, а С++14 расширяет эту возможность на все лямбда-выражения и все функции, включая состоящие из множества инструкций. В случае >authAndAccess
это означает, что в С++ 14 мы можем опустить завершающий возвращаемый тип, оставляя только одно ведущее ключевое слово >auto
. При таком объявлении >auto
означает, что имеет место вывод типа. В частности, это означает, что компиляторы будут выводить возвращаемый тип функции из ее реализации:
>template
>auto authAndAccess(Container& с, Index i) // Не совсем
>{ // корректно
> authenticateUser();
> return c[i]; // возвращаемый тип выводится из c[i]
>}
В разделе 1.2 поясняется, что для функций с >auto
-спецификацией возвращаемого типа компиляторы применяют вывод типа шаблона. В данном случае это оказывается проблематичным. Как уже говорилось, >operator[]
для большинства контейнеров с объектами типа >Т
возвращает >Т&
, но в разделе 1.1 поясняется, что в процессе вывода типа шаблона “ссылочность” инициализирующего выражения игнорируется. Рассмотрим, что это означает для следующего клиентского кода:
>std::deque
>…
>authAndAccess(d, 5) = 10; // Аутентифицирует пользователя, воз-
> // вращает d[5], затем присваивает ему
> // значение 10. Код не компилируется!
Здесь >d[5]
возвращает >int&
, но вывод возвращаемого типа >auto
для >authAndAccess
отбрасывает ссылку, тем самым давая возвращаемый тип >int
. Этот >int
, будучи возвращаемым значением функции, является >rvalue
, так что приведенный выше код пытается присвоить этому >rvalue
типа int значение 10. Это запрещено в С++, так что данный код не компилируется.
Чтобы заставить >authAndAccess
работать так, как мы хотим, нам надо использовать для ее возвращаемого типа вывод типа >decltype
, т.е. указать, что >authAndAccess
должна возвращать в точности тот же тип, что и выражение >с[i]
. Защитники С++, предвидя необходимость использования в некоторых случаях правил вывода типа >decltype
, сделали это возможным в С++14 с помощью спецификатора