Эффективный и современный С++. 42 рекомендации по использованию С++11 и С++14 - страница 18
>template
>auto // версия для
>authAndAccess(Container&& с, Index i) // C++11
> -> decltype(std::forward
> authenticateUser();
> return std::forward
>}
Вторым беспокоящим моментом является мое замечание в начале этого раздела о том, что >decltype
почти всегда дает тип, который вы ожидаете, т.е. что он редко преподносит сюрпризы. По правде говоря, вряд ли вы столкнетесь с этими исключениями из правила, если только вы не занимаетесь круглосуточно написанием библиотек.
Чтобы полностью понимать поведение >decltype
, вы должны познакомиться с некоторыми особыми случаями. Большинство из них слишком невразумительны, чтобы быть размещенными в этой книге, но один из них приводит к лучшему пониманию >decltype
и его применения.
Применение >decltype
к имени дает объявленный тип для этого имени. Имена представляют собой lvalue-выражения, но это не влияет на поведение >decltype
. Однако для lvalue-выражений, более сложных, чем имена, >decltype
гарантирует, что возвращаемый тип всегда будет lvalue-ссылкой. Иначе говоря, если lvalue-выражение, отличное от имени, имеет тип >Т
, то >decltype
сообщает об этом типе как об >Т&
. Это редко на что-то влияет, поскольку тип большинства lvalue-выражений в обязательном порядке включает квалификатор lvalue-ссылки. Например, функции, возвращающие lvalue, всегда возвращают lvalue-ссылки.
Однако у этого поведения есть следствия, о которых необходимо знать. В коде
>int x = 0;
>x
является именем переменной, так что >decltype(x)
представляет собой >int
. Однако “заворачивание” имени >x
в скобки — “>(x)
” — дает выражение, более сложное, чем имя. Будучи именем, >x
представляет собой lvalue, и С++ также определяет выражение >(x)
как lvalue. Следовательно, >decltype((x))
представляет собой >int&
. Добавление скобок вокруг имени может изменить тип, возвращаемый для него >decltype
!
В C++11 это просто любопытный факт, но в сочетании с поддержкой в С++14 >decltype (auto)
это означает, что, казалось бы, тривиальные изменения в способе записи инструкции >return
могут повлиять на выводимый тип функции:
>decltype(auto) f1() {
> int x = 0;
> …
> return x; // decltype(x) представляет собой int,
>} // так что f1 возвращает int
>decltype(auto) f2() {
> int x = 0;
> …
> return (x); // decltype((x)) представляет собой int&,
>} // так что f2 возвращает int&
Обратите внимание, что >f2
не только имеет возвращаемый тип, отличный от >f1
, но и возвращает ссылку на локальную переменную! Этот код ведет вас к неопределенному поведению, что вряд ли является вашей целью.
Основной урок состоит в том, чтобы при использовании >decltype(auto)
уделять деталям самое пристальное внимание. Кажущиеся совершенно незначительными детали в выражении, для которого выводится тип, могут существенно повлиять на тип, возвращаемый >decltype(auto)
. Чтобы гарантировать, что выводимый тип — именно тот, который вы ожидаете, используйте методы, описанные в разделе 1.4.
В то же время не забывайте и о более широкой перспективе. Конечно, >decltype
(как автономный, так и в сочетании с >auto
) при выводе типов иногда может привести к сюрпризам, но это не нормальная ситуация. Как правило, >decltype
возвращает тот тип, который вы ожидаете. Это особенно верно, когда >decltype
применяется к именам, потому что в этом случае >decltype
делает именно то, что скрывается в его названии: сообщает объявленный тип (declared type) имени.
• >decltype
почти всегда дает тип переменной или выражения без каких-либо изменений.
• Для lvalue-выражений типа >Т
, отличных от имени, >decltype
всегда дает тип >T&
.
• C++14 поддерживает конструкцию >decltype(auto)
, которая, подобно >auto
, выводит тип из его инициализатора, но выполняет вывод типа с использованием правил >decltype
.
1.4. Как просмотреть выведенные типы
Выбор инструментов для просмотра результатов вывода типа зависит от фазы процесса разработки программного обеспечения, на которой вы хотите получить эту информацию. Мы рассмотрим три возможности: получение информации о выводе типа при редактировании кода, во время компиляции и во время выполнения.