Почему ограниченные перечисления позволяют использовать | оператор при инициализации с использованием ранее назначенных значений?
Я преобразую перечисления с незаданной областью в перечисления с ограниченной областью и наткнулся на головоломку.
Stroustroup, C++ Язык программирования, 4-е издание, Раздел 8.4.1, документирует, что enum-классы с областью видимости неявно преобразуются в целочисленные типы, и предоставляет код для операторов |
и &
в качестве примера того, как использовать static_cast
чтобы обойти это.
Не должна ли следующая инициализация с использованием оператора |
для ранее определенных значений enum
быть недопустимой?
enum class FileCopy {
PreviousHDUs = 1,
CurrentHDU = 2,
FollowingHDUs = 4,
AllHDUs = PreviousHDUs | CurrentHDU | FollowingHDUs,
CurrentHeader = 8
};
int main()
{
std::cout << static_cast<int>( FileCopy::AllHDUs) << "\n";
}
Я проверил это на Wandbox, используя clang и gcc HEAD с --pedantic-errors
, и он компилирует и возвращает ожидаемый результат, 7
. Это не сказать, что это законно, просто это, кажется, принято компиляторами.
Это явно задокументированное поведение? Мне не удалось проанализировать документацию таким образом, чтобы описать это поведение.
Ответы
Ответ 1
[Dcl.enum]/5:
... Если базовый тип является фиксированным, тип каждого перечислителя перед закрывающей скобкой является базовым типом...
То есть каждый перечислитель имеет тип int
, пока не встретится закрывающая скобка. После этого перечислители имеют тип FileCopy
, и вы больше не сможете поразрядно-ИЛИ их вместе, как это.
Ответ 2
В соответствии со стандартом С++ 17 (8.5.13 оператор ИБЛИ с побитовым включением)
1 Выполняются обычные арифметические преобразования (8.3); результат побитовая включающая функция ИЛИ своих операндов. Оператор применяется только к целочисленным или незаданным операндам перечисления.
И (10.2 Объявления перечисления)
-
... Для перечисляемого типа с ограниченным диапазоном базовым типом является int, если это не так явно указано. В обоих этих случаях тип считается фиксированным. После закрывающей скобки спецификатор enum, каждый перечислитель имеет тип своего перечисления. Если базовый тип фиксирован, тип каждого перечислителя до закрывающая скобка является базовым типом и константным выражением в определение перечислителя должно быть преобразованным константным выражением базовый тип
Так что это явно задокументированное поведение.