Каст к enum class

260
26 ноября 2016, 19:04

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

enum class A : size_t
{
   x = 0u,
   y = 1u,
};
// main 
static_cast<A>(0u);

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

Answer 1

Хранение в enum-объекте представимых, но неименованных значений, не является "багом" или "неправильным значением" с точки зрения общей функциональности enum-типов. Если согласно логике вашего кода это - баг, то вам придется контролировать это самостоятельно. Собственно для того в таких ситуациях и требуется явный каст, чтобы привлечь ваше внимание к потенциальной проблеме.

Кстати, единственным "нелегальным" значением, которое можно "протащить" в любой enum-объект без явного каста является как раз таки 0

enum class A : size_t
{
   x = 1u,
   y = 2u,
};
int main()
{
    A a = A();
}
Answer 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 без указания базового типа, то если присваивается значение, используя явное преобразование, которые лежит вне заданного диапазона, то результат является не специфицированным (смотрите первую приведенную в ответе цитату из стандарта).

Answer 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. Просто так проверка будет очевиднее.

READ ALSO
Помогите разобраться с Nearest neighbor search [закрыто]

Помогите разобраться с Nearest neighbor search [закрыто]

Разбираюсь с поиском соседних частиц в программе fluidv3, не мог бы кто-то пояснить как происходит

155
Регулярные выражения с++ и boost::regex

Регулярные выражения с++ и boost::regex

Помогите пожалуйста с регвыражением

189
Не могу понять в чем ошибка [закрыто]

Не могу понять в чем ошибка [закрыто]

По данному целому числу N распечатайте все квадраты натуральных чисел, не превосходящие N, в порядке возрастанияФормат входных данных Вводится...

273