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

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

Без ясного понимания того, как работает вывод типов, эффективное программирование на современном С++ невозможно. Просто есть слишком много контекстов, в которых имеет место вывод типа: в вызовах шаблонов функций, в большинстве ситуаций, в которых встречается ключевое слово >auto, в выражениях >decltype и, начиная с С++14, там, где применяется загадочная конструкция >decltype(auto).

Эта глава содержит информацию о выводе типов, которая требуется каждому разработчику на языке программирования С++. Здесь поясняется, как работает вывод типа шаблона, как строится >auto и как проходит свой путь >decltype. Здесь даже объясняется, как заставить компилятор сделать видимыми результаты своего вывода типа, чтобы убедиться, что компилятор выводит именно тот тип, который вы хотели.

1.1. Вывод типа шаблона

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

Если вы относитесь к числу этих программистов, у меня для вас две новости — хорошая и плохая. Хорошая новость заключается в том, что вывод типов для шаблонов является основой для одной из наиболее привлекательных возможностей современного С++: >auto. Если вас устраивало, как С++98 выводит типы для шаблонов, вас устроит и то, как С++11 выводит типы для >auto. Плохая новость заключается в том, что когда правила вывода типа шаблона применяются в контексте >auto, они оказываются немного менее интуитивными, чем в приложении к шаблонам. По этой причине важно действительно понимать аспекты вывода типов шаблонов, на которых построен вывод типов для >auto. Этот раздел содержит информацию, которую вы должны знать.

Если вы готовы посмотреть сквозь пальцы на применение небольшого количества псевдокода, то можно рассматривать шаблон функции как имеющий следующий вид:

>templateТ>

>void(ParamType param);

Вызов может выглядеть следующим образом:

>f(expr); // Вызов f с некоторым выражением

В процессе компиляции компилятор использует expr для вывода двух типов: типа и типа >ParamType. Эти типы зачастую различны, поскольку >ParamType часто содержит “украшения”, например >const или квалификаторы ссылки. Например, если шаблон объявлен как

>template

>void f(const T& param); // ParamType - const T&

и мы осуществляем вызов

>int x = 0;


>f(x); // Вызов f с параметром int

то выводится как >int, а >ParamType — как >const int&.

Вполне естественно ожидать, что тип, выведенный для , тот же, что и тип переданного функции аргумента, т.е. что — это тип выражения >expr. В приведенном выше примере это так: >x — значение типа >int и выводится как >int. Но вывод не всегда работает таким образом. Тип, выведенный для >T, зависит не только от типа >expr, но и от вида >ParamType. Существует три случая.

• >ParamType представляет собой указатель или ссылку, но не универсальную ссылку. (Универсальные ссылки рассматриваются в разделе 5.2. Пока что все, что вам надо знать, — что они существуют и не являются ни ссылками lvalue, ни ссылками rvalue.)

• >ParamType является универсальной ссылкой.

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

Следовательно, нам надо рассмотреть три сценария вывода. Каждый из них основан на нашем общем виде шаблонов и их вызова:

>templateТ>

>void f(ParamType param);


>f(expr); // Вывод Т и ParamType из expr

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

Простейшая ситуация — когда >ParamType является ссылочным типом или типом указателя, но не универсальной ссылкой. В этом случае вывод типа работает следующим образом.

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

2. Затем выполняется сопоставление типа >expr с >ParamType для определения . Например, если у нас имеются шаблон

>template

>void f(T& param); // param представляет собой ссылку

и объявления переменных

>int x = 27;        // x имеет тип int

>const int cx = x;  // cx имеет тип const int

>const int& rx = x; // rx является ссылкой на x как на const int

то выводимые типы для >param и в различных выводах будут следующими:

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

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

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

Во втором и третьем вызовах обратите внимание, что, поскольку >cx и >rx объявлены как константные значения, выводится как >const int тем самым приводя к типу параметра >const int&. Это важно для вызывающего кода. Передавая константный объект параметру-ссылке, он ожидает, что объект останется неизменным, т.е. что параметр будет представлять собой ссылку на >const. Вот почему передача константного объекта в шаблон, получающий параметр >T&, безопасна: константность объекта становится частью выведенного для типа.

В третьем примере обратите внимание, что несмотря на то, что типом


Еще от автора Скотт Мейерс
Эффективное использование 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 так просто изучить и так удобно использовать, что даже новые и неискушенные пользователи быстро переходят на ОО-подход.