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

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

:

>enum class Status; // Базовый тип — int

Если вас не устраивает значение по умолчанию, вы можете его перекрыть:

>enum class Status: std::uint32_t; // Базовый тип для Status -

>                                  // std::uint32_t (из )

В любом случае компиляторы знают размер перечислителей в перечислении с областью видимости.

Чтобы указать базовый тип для перечисления без области видимости, вы делаете то же, что и для перечисления с областью видимости, и полученный результат может быть предварительно объявлен:

>enum Color: std::uint8_t; // Предварительное объявление

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

>                          // базовый тип - std::uint8_t

Спецификация базового типа может быть указана и в определении >enum:

>enum class Status: std::uint32_t { good = 0,

>                                   failed = 1,

>                                   incomplete = 100,

>                                   corrupt = 200,

>                                   audited = 500,

>                                   indeterminate = 0xFFFFFFFF

>};

С учетом того факта, что >enum с областью видимости устраняет загрязнение пространства имен и невосприимчиво к бессмысленным преобразованиям типов, вас может удивить тот факт, что имеется как минимум одна ситуация, в которой могут быть полезны перечисления без области видимости, а именно — при обращении к полям в кортежах C++11 >std::tuple. Предположим, например, что у нас есть кортеж, содержащий имя, адрес электронной почты и значение репутации пользователя на сайте социальной сети:

>using UserInfo =          // Псевдоним типа; см. раздел 3.3

>std::tuple

>           std::string,   // Адрес

>           std::size_t> ; // Репутация

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

>UserInfo uInfo;                // Объект с типом кортежа

>…

>auto val = std::get<1>(uInfo); // Получение значения поля 1

Как программисту вам приходится отслеживать множество вещей. Вы действительно должны помнить, что поле 1 соответствует адресу электронной почты пользователя? Я думаю, нет. Использование >enum без области видимости для сопоставления имен полей с их номерами позволяет избежать необходимости перегружать память:

>enum UserInfoFields { uiName, uiEmail, uiReputation };


>UserInfo uInfo;                      // Как и ранее

>…

>auto val = std::get<uiEmail>(uInfo); // Значение адреса

Все было бы гораздо сложнее без неявного преобразования значений из >UserInfoFields в тип >std::size_t, который является типом, требующимся для >std::get.

Соответствующий код с применением перечисления с областью видимости существенно многословнее:

>enum class UserInfoFields { uiName, uiEmail, uiReputation };


>UserInfo uInfo; // Как и ранее

>…

>auto val =

> std::get<static_cast(UserInfoFields::uiMail)>

>  (uInfo);

Эта многословность может быть сокращена с помощью функции, которая принимает перечислитель и возвращает соответствующее значение типа >std::size_t, но это немного сложнее. >std::get является шаблоном, так что предоставляемое значение является аргументом шаблона (обратите внимание на применение не круглых, а угловых скобок), так что функция, преобразующая перечислитель в значение >std::size_t, должна давать результат во время компиляции. Как поясняется в разделе 3.9, это означает, что нам нужна функция, являющаяся >constexpr.

Фактически это должен быть >constexpr-шаблон функции, поскольку он должен работать с любыми перечислениями. И если мы собираемся делать такое обобщение, то должны обобщить также и возвращаемый тип. Вместо того чтобы возвращать >std::size_t, мы должны возвращать базовый тип перечисления. Он доступен с помощью свойства типа >std::underlying_type (о свойствах типов рассказывается в разделе 3.3). Наконец мы объявим его как >noexcept (см. раздел 3.8), поскольку мы знаем, что он никогда не генерирует исключений. В результате мы получим шаблон функции >toUType, который получает произвольный перечислитель и может возвращать значение как константу времени компиляции:

>template

>constexpr typename std::underlying_type::type

>toUType(E enumerator) noexcept

>{

> return

>  static_cast

>   std::underlying_type::type>(enumerator);

>}

В С++14 >toUType можно упростить заменой >typename std::underlying_type::type  более изящным >std::underlying_type_t (см. раздел 3.3):

>template // С++14

>constexpr std::underlying_type_t

>toUType(E enumerator) noexcept {

> return static_cast_t>(enumerator);

>}

Еще более изящный возвращаемый тип >auto (см. раздел 1.3) также корректен в С++14:

>template // С++14

>constexpr auto

>toUType(E enumerator) noexcept {

> return static_cast>(enumerator);

>}

Независимо от того, как он написан, шаблон >toUType позволяет нам обратиться к полю кортежа следующим образом:

>auto val = std::get<toUType(UserInfoFields::uiEmail)>(uInfo);

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


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

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


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

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


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

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


Платформа J2Me

Эта книга научит вас, как разрабатывать программное обеспечение для платформы J2ME компании «Sun Microsystems». Эта книга придерживается стиля учебного пособия, это не справочное руководство.Цель — дать вам твердую основу в понятиях и техниках, которая даст вам возможность решиться на самостоятельную разработку качественных приложений.


Виртуальная библиотека 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 «Информационная технология. Процессы жизненного цикла программных средств» с целью учета специфики разработки и документирования программного обеспечения встроенных систем реального времени.