Эффективный и современный С++. 42 рекомендации по использованию С++11 и С++14 | страница 16
>ParamType
является универсальной ссылкойВсе становится менее очевидным в случае шаблонов, принимающих параметры, являющиеся универсальными ссылками. Такие параметры объявляются как ссылки rvalue (т.е. в шаблоне функции, принимающем параметр типа >Т
, объявленным типом универсальной ссылки является >Т&&
), но ведут себя иначе при передаче аргументов, являющихся lvalue. Полностью вопрос рассматривается в разделе 5.2, здесь приводится его сокращенная версия.
• Если >expr
представляет собой lvalue, как >Т
, так и >ParamType
выводятся как lvalue-ссылки. Это вдвойне необычно. Во-первых, это единственная ситуация в выводе типа шаблона, когда Т выводится как ссылка. Во-вторых, хотя >ParamType
объявлен с использованием синтаксиса rvalue-ссылки, его выводимым типом является lvalue-ссылка.
• Если >expr
представляет собой rvalue, применяются “обычные” правила (из случая 1). Примеры
>template
>void f(T&& param); // param является универсальной ссылкой
>int x = 27; // Как и ранее
>const int cx = x; // Как и ранее
>const int& rx = x; // Как и ранее
>f(x); // x - lvalue, так что Т - int&,
> // тип param также является int&
>f(cx); // cx - lvalue, так что Т - const int&,
> // тип param также является const int&
>f(rx); // rx - lvalue, так что Т - const int&,
> // тип param также является const int&
>f(27); // 27 - rvalue, так что Т - int,
> // следовательно, тип param - int&&
В разделе 5.2 поясняется, почему эти примеры работают именно так, а не иначе. Ключевым моментом является то, что правила вывода типов для параметров, являющихся универсальными ссылками, отличаются от таковых для параметров, являющихся lvalue- или rvalue-ссылками. В частности, когда используются универсальные ссылки, вывод типов различает аргументы, являющиеся lvalue, и аргументы, являющиеся rvalue. Этого никогда не происходит для неуниверсальных ссылок.
>ParamType
не является ни указателем, ни ссылкойКогда >ParamType
не является ни указателем, ни ссылкой, мы имеем дело с передачей по значению:
>template
>void f(T param); // param передается по значению
Это означает, что >param
будет копией переданного функции — совершенно новым объектом. Тот факт, что >param
будет совершенно новым объектом, приводит к правилам, которые регулируют вывод >Т
из >expr
.
1. Как и ранее, если типом >expr
является ссылка, ссылочная часть игнорируется.