Читаем Язык программирования C++. Пятое издание полностью

Проблема в том, что j передается параметру t1 шаблона flip1. Этот параметр имеет простой, не ссылочный тип int, а не int&. Таким образом, этот вызов создает следующий экземпляр шаблона flip1:

void flip1(void(*fcn)(int, int&), int t1, int t2);

Значение j копируется в t1. Ссылочный параметр в функции f() связан с t1, а не с j

Определение параметров функции, хранящих информацию типа

Чтобы передать ссылку через функцию, необходимо переписать ее так, чтобы параметры сохраняли принадлежность своих аргументов к l-значениям. Немного поразмыслив, можно предположить, что константность аргументов также необходимо сохранить.

Всю информацию о типе аргумента можно сохранить, определив соответствующий ему параметр функции как ссылку на r-значение параметра типа шаблона. Использование ссылочного параметра (l- или r-значение) позволяет сохранить константность, поскольку спецификатор const в ссылочном типе нижнего уровня. Благодаря сворачиванию ссылок (см. раздел 16.2.5), если определить параметры функции как T1&& и T2&&, можно сохранить принадлежность к l- или r-значениям аргументов функции (см. раздел 16.2.5):

template

void flip2(F f, T1 &&t1, T2 &&t2) {

 f(t2, t1);

}

Как и прежде, если происходит вызов flip2(f, j, 42), l-значение j передается параметру t1. Однако в функции flip() для T1 выводится тип int&, а значит, тип t1 сворачивается в int&. Ссылка t1 связана с j. Когда функция flip() вызывает функцию f(), ссылочный параметр v2 в функции f() привязан к t1, который, в свою очередь, привязан к j. Когда функция f() осуществляет инкремент v2, это изменяет значение j.

Параметр функции, являющийся ссылкой на r-значение параметра типа шаблона (т.е. Т&&), сохраняет константность и принадлежность к l- или r-значениям соответствующих ему аргументов.

Эта версия функции flip() решает одну половину проблемы. Она работает прекрасно с функциями, получающими ссылки на l-значение, но неприменима для вызова функций с параметрами ссылок на r-значение. Например:

void g(int &&i, int& j) {

 cout << i << " " << j << endl;

}

Если попытаться вызывать функцию g() через функцию flip(), то для параметра ссылки на r-значение функции g() будет передан параметр t2. Даже если функции flip() было передано r-значение, функции g() будет передан параметр, носящий в функции flip() имя t2:

flip2(g, i, 42); // ошибка: нельзя инициализировать int&& из l-значения

Параметр функции, как и любая другая переменная, является выражением l-значения (см. раздел 13.6.1). В результате вызов функции g() в функции flip() передает l-значение параметру ссылки на r-значение функции g().

Использование функции std::forward() для сохранения информации типа в вызове

Чтобы передать функции flip() параметры способом, сохраняющим типы первоначальных аргументов, можно использовать новую библиотечную функцию forward(). Как и функция move(), функция forward() определяется в заголовке utility. В отличие от функции move(), функцию forward() следует вызывать с явным аргументом шаблона (см. раздел 16.2.2). Для этого явного аргумента типа функция forward() возвращает ссылку на r-значение. Таким образом, типом возвращаемого значения функции forward будет Т&&.

Обычно функцию forward() используют для передачи параметра функции, который определен как ссылка на r-значение, параметру типа шаблона. Благодаря сворачиванию ссылок для типа возвращаемого значения функция forward() сохраняет характер (l- или r-значение) переданного ей аргумента:

template intermediary(Type &&arg) {

 finalFcn(std::forward(arg)); // ...

}

Здесь Type используется как тип явного аргумента шаблона функции forward() (выводимый из arg). Поскольку arg — это ссылка на r-значение для параметра типа шаблона, параметр Type представит всю информацию типа в аргументе, переданном параметру arg. Если этот аргумент будет r-значением, то параметр Type будет иметь обычный (не ссылочный) тип и функция forward() возвратит Type&&. Если аргумент будет l-значением, то (благодаря сворачиванию ссылок) типом параметра Type будет ссылка на l-значение. В данном случае типом возвращаемого значения будет ссылка на r-значение для типа ссылки на l-значение. Снова благодаря сворачиванию ссылок (на сей раз для типа возвращаемого значения) функция forward() возвратит тип ссылки на l-значение.

При использовании с параметром функции, являющимся ссылкой на r-значение для параметра типа шаблона (Т&&), функция forward() сохраняет все подробности типа аргумента.

Перепишем первоначальную функцию, используя на этот раз функцию forward():

template

Перейти на страницу:

Похожие книги

Adobe Flash. Создание аркад, головоломок и других игр с помощью ActionScript
Adobe Flash. Создание аркад, головоломок и других игр с помощью ActionScript

Данная книга посвящена программированию игр с помощью ActionScript. Здесь вы найдете подробные указания, необходимые для создания самых разных игр – аркад, головоломок, загадок и даже игровых автоматов. В тексте приведены исходные коды программ и детальные, доступно изложенные инструкции. Базовые принципы программирования ActionScript рассматриваются на примере игр, однако вы без труда сможете применить полученные знания и для разработки неигровых проектов, таких как Web-дизайн и реклама. Рекомендации Гэри Розенцвейга помогут вам не только придумывать занимательные игры и размещать их на Web-сайте, но и оптимизировать скорость их работы, а также защищать свои творения от несанкционированного копирования. Представленный в книге код несложно изменить для использования в других программах.Книга предназначена для широкого круга читателей – создателей анимационных роликов, художников-оформителей, программистов и разработчиков Web-сайтов. Издание может также выступать в качестве практического пособия по изучению ActionScript.

Гэри Розенцвейг

Программирование, программы, базы данных / Программирование / Книги по IT
Секреты приложений Google
Секреты приложений Google

Даже продвинутые пользователи Интернета не подозревают о тех огромных возможностях, которые предоставляют сервисы Google. Автор рассказывает о таких «секретах» сервисов, которые просто немедленно хочется использовать! Создавать сайты и презентации, бродить по улочкам Парижа, изучать звездное небо – все это доступно каждому, кто сидит у экрана монитора и имеет доступ в Интернет. Книга научит вас работать с веб-приложениями и тысячекратно увеличить свои возможности с помощью новейших технологий. Она написана легким, доступным языком и не требует от читателя наличия каких-либо специальных знаний. Книга содержит множество примеров, иллюстраций и будет полезна всем, кто не стоит на месте и стремится сделать свою жизнь более насыщенной и интересной.

Денис Балуев , Денис Игоревич Балуев

Программирование, программы, базы данных / Интернет / Программное обеспечение / Книги по IT