Почему isocpp позволяет нам превышать значения класса enum? - PullRequest
0 голосов
/ 06 июня 2018

Я обнаружил множество интересных вещей при программировании, и одна из них:

enum class Foo {
  FOO_THING,
  FOO_TOO
};

int main() {
  Foo foo {'d'};    // It is OK
  Foo foo2 {3};    // and that one too
}

Отладчик говорит, что его значение:

foo:  (unknown: 100)
foo2: (Foo::FOO_TOO | unknown: 2)

Не могли бы вы сказать мнеПочему разрешено инициализировать Foo со значениями, которые превышают объявленные значения класса enum?

Версия и команда компилятора:

Compiler GCC (g++ (Ubuntu 7.3.0-21ubuntu1~16.04) 7.3.0)
$ g++ -Wall -std=c++17 foo.cpp

Я действительно хочу знать причину создания этого механизма инициализации в C ++ 17?

Насколько я знаю enumкласс создан, чтобы пользователи не могли использовать перечисления таким образом.

Ответы [ 3 ]

0 голосов
/ 06 июня 2018

Не могли бы вы сказать, почему разрешается инициализировать Foo со значениями, которые превышают объявленные значения класса enum?

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

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

Этона самом деле не соответствует действительности - существует класс enum, который не может неявным образом привести enum TO integer, а не наоборот.Обратите внимание, что неявное приведение int к clas enum не представляет большой возможной угрозы.

Обратите внимание, что явное приведение является вполне допустимым и иногда полезным.

Перечисляет как битовые флаги

Иногда перечисления могут использоваться в качестве битовых флагов

enum class O{
    NOTHING = 0,
    VERBOSE = 1,
    QUIET = 2,
    LOG = 4
};

Теперь представьте, что вы хотите передать свои параметры, но хотите, чтобы ваш вывод был зарегистрирован и подробен.Таким образом, вы должны пройти 4 |1 = 5. Это превышает значение перечисления.Для меня это только допустимо (в некоторой степени, есть лучшие решения этой проблемы) использование class enum, превышающее максимальное значение.

0 голосов
/ 06 июня 2018

[dcl.enum] / 8:

Для перечисления, базовый тип которого является фиксированным, значения перечисления являются значениями базового типа.

Все enum class имеют фиксированный базовый тип;либо явное, либо int, если не указано явно.

Таким образом, они гарантированно смогут хранить все, что может их базовый тип.

Перечисления с незаданной областью (enum без class или struct) имеют разные правила;их действительные значения в основном являются двоичным кубом дополнения 2s значений перечислителя.Если бы ваше перечисление было незаданным, его значение равным 3. не было бы переносимым.

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

Вы, вероятно, могли бы сделать предложение для строгого enum, которое может быть только в названных государствах, если вы видите огромныйпреимущество от этого.

Для перечислений без области действия: [dcl.enum] 7.2 / 8

Для перечисления, базовый тип которого является фиксированным, значения перечисления являются значениямибазового типа.В противном случае для перечисления, где e_min - наименьший перечислитель, а e_max - наибольший, значения перечисления - это значения в диапазоне от b_min до b_max, определяемые следующим образом: пусть K будет 1 для представления дополнения до двух и 0 для единицыдополнение или представление величины знака.b_max является наименьшим значением, большим или равным max (| e_min | - K, | e_max |) и равным 2 ^ M - 1, где M - неотрицательное целое число.b_min равен нулю, если e_min неотрицателен, и - (b_max + K) в противном случае.Размер наименьшего битового поля, достаточного для хранения всех значений типа перечисления, равен max (M, 1), если b_min равен нулю, и M + 1 в противном случае.Можно определить перечисление, значения которого не определены ни одним из перечислителей.Если список перечислителя пуст, значения перечисления такие, как если бы перечисление имело единственный перечислитель со значением 0

[expr.static.cast] 5.2.8 / 10:

Значение целочисленного типа или типа перечисления может быть явно преобразовано в тип перечисления.Значение не изменяется, если исходное значение находится в диапазоне значений перечисления (7.2).В противном случае результирующее значение не определено (и может не входить в этот диапазон).

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

enum foo{zero, one};

базовый тип foo будет неким целочисленным типом, а foo совместим с макетом этого интегрального типа, и этот целочисленный тип может содержать 2 только файл, но преобразование 2 в foo приводит к foo хранение неопределенного значения.

0 голосов
/ 06 июня 2018

Каждый enum class имеет базовый тип , который должен быть как минимум на один байт больше.Любая односимвольная константа, такая как 'd', помещается в байте.

(C ++ определяет байт как объем памяти для одного символа. 8 бит называются «октетами» на жаргоне C ++)

Обратите внимание, что для "старых" перечислений диапазон определяется более ограниченно, но это влияет на правила преобразования.У вас все еще есть базовый тип, и он должен быть размером в один байт.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...