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

Скотт Мейерс

  primeFactors(c);    // функцию, ожидающую std::size_t

}

Если вы хотите честно выполнить преобразование из Color в другой тип, сделайте то же, что вы всегда делаете для осуществления своих грязных желаний, — воспользуйтесь явным приведением типа:

if (static_cast<double>(c) < 14.5) { // Странный, но

                                     // корректный код

 auto factors =       // Сомнительно, но компилируется

  primeFactors (static_cast<std::size_t>(c));

}

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

enum Color;       // Ошибка!

enum class Color; // OK

Это заблуждение. В С++11 перечисления без областей видимости также могут быть объявлены предварительно, но только с помощью небольшой дополнительной работы, которая вытекает из того факта, что каждое перечисление в С++ имеет целочисленный базовый тип (underlying type), который определяется компилятором. Для перечисления без области видимости наподобие Color

enum Color { black, white, red };

компилятор может выбрать в качестве базового типа char, так как он должен представить всего лишь три значения. Однако некоторые перечисления имеют куда больший диапазон значений, например:

enum Status { good = 0,

              failed = 1,

              incomplete = 100,

              corrupt = 200,

              indeterminate = 0xFFFFFFFF

};

Здесь должны быть представлены значения в диапазоне от 0 до 0xFFFFFFFF. За исключением необычных машин (где char состоит как минимум из 32 битов), компилятор выберет для предоставления значений Status целочисленный тип, больший, чем char.

Для эффективного использования памяти компиляторы часто выбирают наименьший базовый тип, которого достаточно для представления значений перечислителей. В некоторых случаях, когда компиляторы выполняют оптимизацию по скорости, а не по размеру, они могут выбрать не наименьший допустимый тип, но при этом они, определенно, захотят иметь возможность оптимизации размера. Для этого С++98 поддерживает только определения enum (в которых перечислены все значения); объявления enum не разрешены. Это позволяет компиляторам выбирать базовый тип для каждого enum до его использования.

Но невозможность предварительного объявления enum имеет свои недостатки. Наиболее важным из них, вероятно, является увеличение зависимостей при компиляции. Вновь обратимся к перечислению Status:

enum Status { good = 0,

              failed = 1,

              incomplete = 100,

              corrupt = 200,

              indeterminate = 0xFFFFFFFF

};

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

enum Status { good = 0,

              failed = 1,

              incomplete = 100,

              corrupt = 200,

              audited = 500,