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

стр.

контейнера тип зависит от самого контейнера.

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

>template // Работает, но

>auto authAndAccess(Container& с, Index i)    // требует

> ->decltype(c[i])                            // уточнения

>{

> authenticateUser();

> return c[i];

>}

Использование >auto перед именем функции не имеет ничего общего с выводом типа. На самом деле оно указывает, что использован синтаксис С++11 — завершающий возвращаемый тип (trailing return type), т.е. что возвращаемый тип функции будет объявлен после списка параметров (после “>->”). Завершающий возвращаемый тип обладает тем преимуществом, что в спецификации возвращаемого типа могут использоваться параметры функции. В >authAndAccess, например, мы указываем возвращаемый тип с использованием и >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 с помощью спецификатора >decltype(auto). То, что изначально может показаться противоречием (>decltypeи>auto?), в действительности имеет смысл: >auto указывает, что тип должен быть выведен, а >decltype говорит о том, что в процессе вывода следует использовать правила >decltype. Итак, можно записать >authAndAccess следующим образом:

>template // С++14; работает,

>decltype(auto)                               // но все еще

>authAndAccess(Containers с, Index i)         // требует

>{                                            // уточнения

> authenticateUser();

> return c[i];

>}

Теперь >authAndAccess действительно возвращает то же, что и >c[i]. В частности, в распространенном случае, когда