Страницы

Поиск по вопросам

вторник, 24 декабря 2019 г.

Преобразование к enum class

#cpp #cpp11 #enum


Законно ли преобразование значения типа underlying type к типу моего enum class?
Т.е. можно ли делать так?

enum class A : size_t
{
   x = 0u,
   y = 1u,
};

// main 
static_cast(0u);


Заметил интересную вещь, если пытаться преобразовывать значения, которые есть в перечислении
(0u и 1u), то в отладчике будут верные буквенные значения (x и y), а если пытаться
преобразовать не присутствующее там число, но всё ещё типа size_t, то никакой ошибки
компиляции нет, но в отладчике не показывается ни x, ни y, а просто это число, т.е.
имеем сложнообнаружимую ошибку. Если преобразование законно, можно ли как-то контролировать
правильность значений?
    


Ответы

Ответ 1



Хранение в enum-объекте представимых, но неименованных значений, не является "багом" или "неправильным значением" с точки зрения общей функциональности enum-типов. Если согласно логике вашего кода это - баг, то вам придется контролировать это самостоятельно. Собственно для того в таких ситуациях и требуется явный каст, чтобы привлечь ваше внимание к потенциальной проблеме. Кстати, единственным "нелегальным" значением, которое можно "протащить" в любой enum-объект без явного каста является как раз таки 0 enum class A : size_t { x = 1u, y = 2u, }; int main() { A a = A(); }

Ответ 2



Согласно стандарту С++ (5.2.9 Static cast) 10 A value of integral or enumeration type can be explicitly converted to an enumeration type. The value is unchanged if the original value is within the range of the enumeration values (7.2). Otherwise, the resulting value is unspecified (and might not be in that range). A value of floating-point type can also be converted to an enumeration type. The resulting value is the same as converting the original value to the underlying type of the enumeration (4.9), and subsequently to the enumeration type. А также (7.2 Enumeration declarations) 5 Each enumeration defines a type that is different from all other types. Each enumeration also has an underlying type. The underlying type can be explicitly specified using enum-base; if not explicitly specified, the underlying type of a scoped enumeration type is int. In these cases, the underlying type is said to be fixed. и (там же) 7 For an enumeration whose underlying type is fixed, the values of the enumeration are the values of the underlying type. Следовательно любое значение базового фиксированного типа перечисление может быть явно преобразовано к типу перечисления, хотя в списке перечислелителей такого перечислителя не объявлено. Когда же базовый целочисленный тип не фиксирован, то есть используется так называемое unscoped enumeration без указания базового типа, то если присваивается значение, используя явное преобразование, которые лежит вне заданного диапазона, то результат является не специфицированным (смотрите первую приведенную в ответе цитату из стандарта).

Ответ 3



Как уже сказано в других ответах: каст, с точки зрения языка в данном случае вполне легален. Если же нужно проверять факт соответствия целочисленной переменной одной из констант enum, то самый простой способ - это дать константам значения из непрерывного диапазона и проверять попадание кастуемой целочисленной переменной в этот диапазон. Например, так: enum class A : size_t { x = 0u, min = x, y = 1u, z = 2u, max = z }; size_t s = ...; if(A::min <= s && s <= A::max) { // есть именованное значение для s } else { // для s именованного значения нет } Задавать при этом дополнительные имена max и min вовсе не обязательно, можно использовать x, z. Просто так проверка будет очевиднее.

Комментариев нет:

Отправить комментарий