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

стр.

>

>f(cx);                  // Т - int, тип param - const int&

>f(rx);                  // Т - int, тип param - const int&

Как и ранее, “ссылочность” >rx при выводе типа игнорируется.

Если бы >param был указателем (или указателем на >const), а не ссылкой, все бы работало, по сути, точно так же:

>template

>void f(T* param);   // Теперь param является указателем


>int x = 27;         // Как и ранее

>const int *px = &x; // px - указатель на x, как на const int


>f(&x);              // Т - int, тип param - int*

>f(px);              // Т - const int, тип param - const int*

Сейчас вы можете обнаружить, что давно усердно зеваете, потому что все это очень скучно, правила вывода типов в С++ работают так естественно для ссылок и указателей, что все просто очевидно! Это именно то, что вы хотите от системы вывода типов.

Случай 2. >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. Этого никогда не происходит для неуниверсальных ссылок.

Случай 3. >ParamType не является ни указателем, ни ссылкой

Когда >ParamType не является ни указателем, ни ссылкой, мы имеем дело с передачей по значению:

>template

>void f(T param); // param передается по значению

Это означает, что >param будет копией переданного функции — совершенно новым объектом. Тот факт, что >param будет совершенно новым объектом, приводит к правилам, которые регулируют вывод из >expr.

1. Как и ранее, если типом >expr является ссылка, ссылочная часть игнорируется.

2. Если после отбрасывания ссылочной части >expr является >const, это также игнорируется. Игнорируется и модификатор >volatile (объекты >volatile являются редкостью и в общем случае используются только при реализации драйверов устройств; детальную информацию на эту тему вы найдете в разделе 7.6.)

Таким образом, получаем следующее:

>int x = 27;        // Как и ранее

>const int cx = x;  // Как и ранее

>const int& rx = x; // Как и ранее

>f(x);              // Типами и Т, и param являются int

>f(cx);             // Типами и Т, и param вновь являются int

>f(rx);             // Типами и Т, и param опять являются int

Обратите внимание, что даже несмотря на то, что >cx и >rx представляют константные значения, >param не является >const. Это имеет смысл. >param представляет собой объект, который полностью независим от