С другой стороны, когда происходит вызов функции f3()
i
, типом T
будет int&
. Когда определяется и инициализируется локальная переменная t
, у нее будет тип int&
. Инициализация переменной t
свяжет ее с параметром val
. При присвоении переменной t
одновременно изменяется и параметр val
. В этом экземпляре функции f3()
оператор if
всегда будет возвращать значение true
.На удивление сложно написать правильный код, когда задействованные типы могут быть простыми (не ссылочными) типами или ссылочными типами (хотя такие классы трансформации типов, как remove_reference
На практике параметры в виде ссылки на r-значение используются в одном из двух случаев: либо когда шаблон перенаправляет свои аргументы, ли когда шаблон перегружается. Перенаправление рассматривается в разделе 16.2.7, а перегрузка шаблона в разделе 16.3, а пока достаточно знать, что стоит обратить внимание на то, что шаблоны функций, использующие ссылки на r-значение, зачастую используют перегрузку таким же образом, как описано в разделе 13.6.3:
template
//
template
//
Подобно нешаблонным функциям, первая версия будет связана с изменяемым r-значением, а вторая с l-значением или константным r-значением.
Упражнение 16.42
. Определите типыТ
и val
в каждом из следующих вызовов:template
int i = 0; const int ci = i;
(a) g(i); (b) g(ci); (c) g(i * ci);
Упражнение 16.43
. Используя определенную в предыдущем упражнении функцию, укажите, каким будет параметр шаблонаg()
при вызове g(i = ci)
?Упражнение 16.44
. Используя те же три вызова, что и в первом упражнении, определите типыT
, если параметр функции g()
объявляется как T
(а не Т&&
) и как const Т&
?Упражнение 16.45
. С учетом следующего шаблона объясните происходящее при вызове функцииg()
с таким литеральным значением, как 42, и с переменной типа int
?template
std::move()
Библиотечная функция move()
move()
можно использовать, не понимая механизма работы используемого ею шаблона. Однако изучение работы функции move()
может помочь понять и использовать шаблоны.В разделе 13.6.2 обращалось внимание на то, что, хотя и нельзя непосредственно привязать ссылку на r-значение к l-значению, функцию move()
move()
может получать аргументы, по существу, любого типа, нет ничего удивительного в том, что move()
— это шаблон функции.std::move()
Стандартное определение функции move()
//
//
//
template
typename remove_reference
//
return static_cast
}
Этот код короток, но сложен. В первую очередь, параметр функции move()
Т&&
является ссылкой на r-значение типа параметра шаблона. Благодаря сворачиванию ссылок этот параметр может соответствовать аргументу любого типа. В частности, функции move()
можно передать либо l-, либо r-значение:string s1("hi!"), s2;
s2 = std::move(string("bye!")); //
s2 = std::move(s1); //
//
std::move()
В первом присвоении аргумент функции move()
string("bye")
класса string
. Как уже упоминалось, при передаче r-значения ссылочному r-значению параметра функции выведенный из этого аргумента тип является ссылочным типом (см. раздел 16.2.5). Таким образом, в вызове std::move(string("bye!"))
:• выведенным типом T
string
;• следовательно, экземпляр шаблона remove_reference
string
;