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