Эффективный и современный С++. 42 рекомендации по использованию С++11 и С++14 | страница 28
>std::deque
>// Делаем копию пятого элемента deque, возвращаемого
>// функцией makeStringDeque
>auto s = authAndAccess(makeStringDeque(), 5);
Поддержка такого использования означает, что мы должны пересмотреть объявление функции >authAndAccess
, которая должна принимать как lvalue, так и rvalue. Можно использовать перегрузку (одна функция объявлена с параметром, представляющим собой lvalue-ссылку, а вторая — с параметром, представляющим собой rvalue-ссылку), но тогда нам придется поддерживать две функции. Избежать этого можно, если у нас будет функция >authAndAccess
, использующая ссылочный параметр, который может быть связан как с lvalue, так и с rvalue, и в разделе 5.2 поясняется, что это именно то, что делают универсальные ссылки. Таким образом, >authAndAccess
может быть объявлена следующим образом:
>template
>decltype(auto) authAndAccess(Container&& с, // универсальная
> Index i); // ссылка
В этом шаблоне мы не знаем, с каким типом контейнера работаем, и точно так же не знаем тип используемых им индексных объектов. Использование передачи по значению для объектов неизвестного типа обычно сопровождается риском снижения производительности из-за ненужного копирования, проблемами со срезкой объектов (см. раздел 8.1) и насмешками коллег. Но в случае индексов контейнеров, следуя примеру стандартной библиотеки для значений индексов (например, в >operator[]
для >std::string
, >std::vector
и std::deque) это решение представляется разумным, так что мы будем придерживаться для них передачи по значению.
Однако нам нужно обновить реализацию шаблона для приведения его в соответствие с предостережениями из раздела 5.3 о применении >std::forward
к универсальным ссылкам:
>template
>decltype(auto) // версия для
>authAndAccess(Container&& с, Index i) // С++14
>{
> authenticateUser();
> return std::forward
>}
Этот код должен делать все, что мы хотели, но он требует компилятора С++14. Если у вас нет такового, вам следует использовать версию шаблона для С++11. Она такая же, как и ее аналог С++14, за исключением того, что вы должны самостоятельно указать возвращаемый тип:
>template