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



. То, что изначально может показаться противоречием (>decltypeи>auto?), в действительности имеет смысл: >auto указывает, что тип должен быть выведен, а >decltype говорит о том, что в процессе вывода следует использовать правила >decltype. Итак, можно записать >authAndAccess следующим образом:

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

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

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

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

> authenticateUser();

> return c[i];

>}

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

Использование >decltype(auto) не ограничивается возвращаемыми типами функций. Это также может быть удобно для объявления переменных, когда вы хотите применять правила вывода типа >decltype к инициализирующему выражению:

>Widget w;

>const Widget& cw = w;


>auto myWidget1 = cw;           // Вывод типа auto:


>                               // тип myWidget1 - Widget

>decltype(auto) myWidget2 = cw; // Вывод типа decltype:

>                               // тип myWidget2 - const Widget&

Я знаю, что вас беспокоят два момента. Один из них — упомянутое выше, но пока не описанное уточнение >authAndAccess. Давайте, наконец-то, разберемся в этом вопросе. Еще раз посмотрим на версию >authAndAccess в С++14:

>template

>decltype(auto) authAndAccess(Container& с, Index i);

Контейнер передается как lvalue-ссылка на неконстантный объект, поскольку возвращаемая ссылка на элемент контейнера позволяет клиенту модифицировать этот контейнер. Но это означает, что этой функции невозможно передавать контейнеры, являющиеся rvalue. rvalue невозможно связать с lvalue-ссылками (если только они не являются lvalue-ссылками на константные объекты, что в данном случае очевидным образом не выполняется).

Надо сказать, что передача контейнера, являющегося rvalue, в >authAndAccess является крайним случаем. Такой rvalue-контейнер, будучи временным объектом, обычно уничтожается в конце инструкции, содержащей вызов >authAndAccess, а это означает, что ссылка на элемент в таком контейнере (то, что должна вернуть функция >authAndAccess) окажется “висячей” в конце создавшей ее инструкции. Тем не менее передача временного объекта функции