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

Скотт Мейерс

              indeterminate = 0xFFFFFFFF

};

то, вероятно, придется перекомпилировать всю систему полностью, даже если только одна подсистема — возможно, одна-единственная функция! — использует это новое значение. Это одна из тех вещей, которые программисты просто ненавидят. И это та вещь, которую исключает возможность предварительного объявления enum в С++11. Например, вот совершенно корректное объявление enum с областью видимости, и функции, которая получает его в качестве параметра:

enum class Status;                 // Предварительное объявление

void continueProcessing(Status s); // и его использование

Заголовочный файл, содержащий эти объявления, не требует перекомпиляции при пересмотре определения Status. Кроме того, если изменено перечисление Status (например, добавлено значение audited), но поведение continueProcessing не изменилось (например, потому что continueProcessing не использует значение audited), то не требуется и перекомпиляция реализации continueProcessing.

Но если компилятор должен знать размер enum до использования, то как могут перечисления С++ 11 быть предварительно объявлены, в то время как перечисления С++98 этого не могут? Ответ прост: базовый тип перечислений с областью видимости всегда известен, а для перечислений без областей видимости вы можете его указать.

По умолчанию базовым типом для enum с областью видимости является int:

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

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

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

                                  // std::uint32_t (из <cstdint>)

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

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

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,   // Имя