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

Шрифт
Интервал

объекта IPv4Header компилируется без проблем:

>void f(std::size_t sz); // Вызываемая функция

>IPv4Header h;

>…

>f(h.totalLength);       // Все в порядке

Однако попытка передать >h.totalLength в >f через >fwd — это совсем другая история:

>fwd(h.totalLength);     // Ошибка!

Проблема заключается в том, что параметр функции >fwd представляет собой ссылку, а >h.totalLength — неконстантное битовое поле. Это может показаться не столь уж плохим, но стандарт С++ осуждает это сочетание в непривычно ясной форме: “неконстантная ссылка не может быть привязана к битовому полю”. Тому есть превосходная причина. Битовые поля могут состоять из произвольных частей машинных слов (например, биты 3-5 из 32-битного >int), но непосредственно их адресовать нет никакой возможности. Ранее я упоминал, что ссылки и указатели представляют собой одно и то же на аппаратном уровне, и просто так же, как нет никакого способа создать указатели на отдельные биты (С++ утверждает, что наименьшей сущностью, которую вы можете адресовать, является >char), нет никакого способа связать ссылку с произвольными битами.

Обходной путь для невозможности прямой передачи битовых полей становится простым, как только вы осознаете, что любая функция, принимающая битовое поле в качестве аргумента, на самом деле получает копию значения битового поля. В конце концов, никакая функция не может привязать ссылку к битовому полю, поскольку не существует указателей на битовые поля. Единственная разновидность параметров, которым могут передаваться битовые поля, — это параметры, передаваемые по значению, и, что интересно, ссылки на >const. В случае передачи по значению вызываемая функция, очевидно, получает копию значения в битовом поле, и оказывается, что в случае параметра, являющегося ссылкой на >const, стандарт требует, чтобы эта ссылка в действительности была привязана к копии значения битового поля, сохраненного в объекте некоторого стандартного целочисленного типа (например, >int). Ссылки на >const не привязываются к битовым полям, они привязываются к “нормальным” объектам, в которые копируются значения битовых полей.

Итак, ключом к передаче битового поля в функцию с прямой передачей является использование того факта, что функция, в которую осуществляется передача, всегда получает копию значения битового поля. Таким образом, вы можете сделать копию самостоятельно и вызвать передающую функцию, передав ей копию. В нашем примере с >IPv4Header код, осуществляющий этот подход, имеет следующий вид:

>// Копирование значения битового поля; см. раздел 2.2

>auto length = static_cast(h.totalLength);

>fwd(length); // Передача копии

Резюме

В большинстве случаев прямая передача работает так, как разрекламировано. Вы редко должны задумываться о ней. Но когда она не работает (разумно выглядящий код не компилируется или, хуже того, компилируется, но работает не так, как вы ожидаете), важно знать о несовершенствах прямой передачи. Не менее важно знать, как эти несовершенства обойти. В большинстве случаев это довольно просто.

Следует запомнить

• Прямая передача неудачна, когда вывод типа не удается выполнить или когда он выводит неверный тип.

• Разновидностями аргументов, которые приводят к неудачам при прямой передаче, являются инициализаторы в фигурных скобках, нулевые указатели, выраженные как >0 или >NULL, целочисленные члены-данные, объявленные как >const static и не имеющие определений, имена шаблонов и перегруженных функций и битовые поля.

Глава 6

Лямбда-выражения

Лямбда-выражения, иногда называемые просто лямбдами (lambdas), существенно изменили правила игры в программировании на С++. Это несколько удивительно, так как они не внесли в язык никаких новых возможностей выражения идей. Все, на что способны лямбда-выражения, вы в состоянии сделать вручную, разве что ценой немного больших усилий по вводу с клавиатуры. Но лямбда-выражения представляют собой очень удобное средство создания функциональных объектов, оказывающее огромное влияние на повседневную разработку программного обеспечения на С++. Без лямбда-выражений алгоритмы “>_if” из STL (например, >std::find_if, >std::remove_if, >std::count_if и др.) обычно работают с самыми тривиальными предикатами, но при доступности лямбда-выражений применение этих алгоритмов резко возрастает. То же самое верно и для алгоритмов, настраиваемых с помощью пользовательской функции сравнения (например, >std::sort, >std::nth_element, >std::lower_bound и др.). Вне STL лямбда-выражения позволяют быстро создавать пользовательские удалители для >std::unique_ptr и >std::shared_ptr (см. разделы 4.1 и 4.2) и делают столь же простыми спецификации предикатов для переменных условий в потоковом API (см. раздел 7.5). Помимо использования в объектах стандартной библиотеки, лямбда-выражения облегчают определение функций обратного вызова “на лету”, функций адаптации интерфейса и контекстно-зависимых функций для разовых вызовов. Лямбда-выражения действительно делают С++ более приятным языком программирования.

Терминология, связанная с лямбда-выражениями, может обескуражить. Лямбда-выражение является именно тем, что написано: выражением. Это часть исходного текста. В приведенном ниже фрагменте выделенная полужирным шрифтом часть представляет собой лямбда-выражение.


Еще от автора Скотт Мейерс
Эффективное использование STL

В этой книге известный автор Скотт Мейерс раскрывает секреты настоящих мастеров, позволяющие добиться максимальной эффективности при работе с библиотекой STL.Во многих книгах описываются возможности STL, но только в этой рассказано о том, как работать с этой библиотекой. Каждый из 50 советов книги подкреплен анализом и убедительными примерами, поэтому читатель не только узнает, как решать ту или иную задачу, но и когда следует выбирать то или иное решение — и почему именно такое.


Как функции, не являющиеся методами, улучшают инкапсуляцию

Когда приходится инкапсулировать, то иногда лучше меньше, чем большеЯ начну со следующего утверждения: Если вы пишете функцию, которая может быть выполнена или как метод класса, или быть внешней по отношению к классу, Вы должны предпочесть ее реализацию без использования метода. Такое решение увеличивает инкапсуляцию класса. Когда Вы думаете об использовании инкапсуляции, Вы должны думать том, чтобы не использовать методы.Удивлены? Читайте дальше.


Рекомендуем почитать
Pro Git

Разработчику часто требуется много сторонних инструментов, чтобы создавать и поддерживать проект. Система Git — один из таких инструментов и используется для контроля промежуточных версий вашего приложения, позволяя вам исправлять ошибки, откатывать к старой версии, разрабатывать проект в команде и сливать его потом. В книге вы узнаете об основах работы с Git: установка, ключевые команды, gitHub и многое другое.В книге рассматриваются следующие темы:основы Git;ветвление в Git;Git на сервере;распределённый Git;GitHub;инструменты Git;настройка Git;Git и другие системы контроля версий.


Java 7

Рассмотрено все необходимое для разработки, компиляции, отладки и запуска приложений Java. Изложены практические приемы использования как традиционных, так и новейших конструкций объектно-ориентированного языка Java, графической библиотеки классов Swing, расширенной библиотеки Java 2D, работа со звуком, печать, способы русификации программ. Приведено полное описание нововведений Java SE 7: двоичная запись чисел, строковые варианты разветвлений, "ромбовидный оператор", NIO2, новые средства многопоточности и др.


MFC и OpenGL

В книге рассказывается история главного героя, который сталкивается с различными проблемами и препятствиями на протяжении всего своего путешествия. По пути он встречает множество второстепенных персонажей, которые играют важные роли в истории. Благодаря опыту главного героя книга исследует такие темы, как любовь, потеря, надежда и стойкость. По мере того, как главный герой преодолевает свои трудности, он усваивает ценные уроки жизни и растет как личность.


Симуляция частичной специализации

В книге рассказывается история главного героя, который сталкивается с различными проблемами и препятствиями на протяжении всего своего путешествия. По пути он встречает множество второстепенных персонажей, которые играют важные роли в истории. Благодаря опыту главного героя книга исследует такие темы, как любовь, потеря, надежда и стойкость. По мере того, как главный герой преодолевает свои трудности, он усваивает ценные уроки жизни и растет как личность.


Обработка событий в С++

В книге рассказывается история главного героя, который сталкивается с различными проблемами и препятствиями на протяжении всего своего путешествия. По пути он встречает множество второстепенных персонажей, которые играют важные роли в истории. Благодаря опыту главного героя книга исследует такие темы, как любовь, потеря, надежда и стойкость. По мере того, как главный герой преодолевает свои трудности, он усваивает ценные уроки жизни и растет как личность.


Питон — модули, пакеты, классы, экземпляры

Python - объектно-ориентированный язык сверхвысокого уровня. Python, в отличии от Java, не требует исключительно объектной ориентированности, но классы в Python так просто изучить и так удобно использовать, что даже новые и неискушенные пользователи быстро переходят на ОО-подход.