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

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

> << '\n'; // для x и y

Этот подход основан на том факте, что вызов >typeid для такого объекта, как >x или >y, дает объект >std: :type_info, а он имеет функцию-член >name, которая дает С-строку (т.е. >const char*), представляющую имя типа.

Не гарантируется, что вызов >std::type_info::name вернет что-то разумное, но его реализации изо всех сил пытаются быть полезными. Уровень этой полезности варьируется от компилятора к компилятору. Компиляторы GNU и Clang, например, сообщают, что тип >x — это “>i” а тип >y — “>PKi”. Эти результаты имеют смысл, если вы будете знать, что “>i” у данных компиляторов означает “>int”, а “>PK” — “указатель на константу”.

(Оба компилятора поддерживают инструмент >c++filt, который расшифровывает эти имена.) Компилятор Microsoft генерирует менее зашифрованный вывод: “>int” для >x и “i>nt const *”для >y.

Поскольку это корректные результаты для типов >x и >y, вы можете подумать, что задача получения информации о типах решена, но не делайте скоропалительных выводов. Рассмотрим более сложный пример:

>template             // Шаблонная функция,

>void f(const T& param);          // вызываемая далее


>std::vector createVec(); // Фабричная функция


>const auto vw = createVec();     // Инициализация vw возвратом

>                                 // фабричной функции


>if (!vw.empty()) {

> f(&vw[0]);                      // Вызов f

>}

Этот код, включающий пользовательский тип (>Widget), контейнер STL (>std::vector) и переменную auto (>vw), является более представительным и интересным примером. Было бы неплохо узнать, какие типы выводятся для параметра типа шаблона и для параметра param функции >f.

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

>template

>void f(const T& param) {

> using std::cout;


> // Вывод в поток cout типа T:

> cout << "Т = " << typeid(T).name() << '\n';


> // Вывод в поток cout типа param:

> cout << "param = " << typeid(param).name() << '\n';

>}

Выполнимые файлы, полученные с помощью компиляторов GNU и Clang, дают следующий результат:

>Т     = PK6Widget

>param = PK6Widget

Мы уже знаем, что в этих компиляторах >PK означает указатель на константу, так что вся загадка — в цифре >6. Это просто количество символов в следующем за ней имени класса (>Widget). Таким образом, данные компиляторы сообщают нам, что и , и >param имеют один и тот же тип — >const Widget*. Компилятор Microsoft согласен:

>Т     = class Widget const *

>param = class Widget const *

Три независимых компилятора дают одну и ту же информацию, что свидетельствует о том, что эта информация является точной. Но давайте посмотрим более внимательно. В шаблоне >f объявленным типом param является тип >const Т&. В таком случае не кажется ли вам странным, что и , и >param имеют один и тот же тип? Если тип , например, представляет собой >int, то типом >param должен быть >const int& — совершенно другой тип.

К сожалению, результат >std::type_info::name ненадежен. Например, в данном случае тип, который все три компилятора приписывают >param, является неверным. Кроме того, он по сути обязан быть неверным, так как спецификация >std::type_info::name разрешает, чтобы тип рассматривался как если бы он был передан в шаблонную функцию по значению. Как поясняется в разделе 1.1, это означает, что если тип является ссылкой, его “ссылочность” игнорируется, а если тип после удаления ссылочности оказывается >const (или >volatile), то соответствующие модификаторы также игнорируются. Вот почему информация о типе >param — который на самом деле представляет собой >const Widget* const& — выводится как >const Widget*. Сначала удаляется ссылочность, а затем у получившегося указателя удаляется константность.

Не менее печально, что информация о типе, выводимая редакторами IDE, также ненадежна — или как минимум ненадежно полезна. Для этого же примера мой редактор IDE сообщает о типе как (я не придумываю!):

>const

>std::_Simple_types

>std::allocator >::_Alloc>::value_type>::value_type *

Тот же редактор IDE показывает, что тип param следующий:

>const std::_Simple_types<...>::value_type *const &

Это выглядит менее страшно, чем тип , но троеточие в средине типа сбивает с толку, пока вы не поймете, что это редактор IDE попытался сказать “Я опускаю все, что является частью типа T”. Ваша среда разработки, быть может, работает лучше моей — если вы достаточно везучий.

Если вы склонны полагаться на библиотеки больше, чем на удачу, то будете рады узнать, что там, где >std::type_info::name и IDE могут ошибаться, библиотека Boost TypeIndex (часто именуемая как Boost.TypeIndex) приведет к успеху. Эта библиотека не является частью стандарта С++, но точно так же частью стандарта не являются ни IDE, ни шаблоны наподобие рассмотренного выше TD. Кроме того, тот факт, что библиотеки Boost (доступные по адресу >boost.org) являются кроссплатформенными, с открытым исходным кодом и с лицензией, разработанной так, чтобы быть приемлемой даже для самых параноидальных юристов, означает, что код с применением библиотек Boost переносим практически так же хорошо, как и код, основанный на стандартной библиотеке.


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

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


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

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


Рекомендуем почитать
Изучаем Java EE 7

Java Enterprise Edition (Java EE) остается одной из ведущих технологий и платформ на основе Java. Данная книга представляет собой логичное пошаговое руководство, в котором подробно описаны многие спецификации и эталонные реализации Java EE 7. Работа с ними продемонстрирована на практических примерах. В этом фундаментальном издании также используется новейшая версия инструмента GlassFish, предназначенного для развертывания и администрирования примеров кода. Книга написана ведущим специалистом по обработке запросов на спецификацию Java EE, членом наблюдательного совета организации Java Community Process (JCP)


Виртуальная библиотека Delphi

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


Обработка баз данных на Visual Basic.NET

Это практическое руководство разработчика программного обеспечения на Visual Basic .NET и ADO.NET, предназначенное для создания приложений баз данных на основе WinForms, Web-форм и Web-служб. В книге описываются практические способы решения задач доступа к данным, с которыми сталкиваются разработчики на Visual Basic .NET в своей повседневной деятельности. Книга начинается с основных сведений о создании баз данных, использовании языка структурированных запросов SQL и системы управления базами данных Microsoft SQL Server 2000.


Исчерпывающее руководство по написанию всплывающих подсказок

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


Программное обеспечение встроенных систем. Общие требования к разработке и документированию

Embedded system software. General requirements for development and documentationСтандарт подготовлен в развитие ГОСТ Р ИСО/МЭК 12207-99 «Информационная технология. Процессы жизненного цикла программных средств» с целью учета специфики разработки и документирования программного обеспечения встроенных систем реального времени.


Как пасти котов. Наставление для программистов, руководящих другими программистами

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