проверка типов в enum - PullRequest
       38

проверка типов в enum

1 голос
/ 29 августа 2009

Я ожидаю, что следующий фрагмент кода будет жаловаться на попытку назначить что-то другое, чем 0,1,2, для переменной Color. Но следующее компилируется, и я получаю вывод

Печать: 3

3

Кто-нибудь может объяснить, почему? Разве enum не предназначен, чтобы быть истинным определяемым пользователем типом? Спасибо.

enum Color { blue=0,green=1,yellow=2};

void print_color(Color x);

int main(){
    Color x=Color(3);

    print_color(x);
    std::cout << x << std::endl;

    return 0;
}

void print_color(Color x)
{
    std::cout << "Printing:" << x << std::endl;
}

Ответы [ 4 ]

4 голосов
/ 29 августа 2009

Поскольку вы вручную приводите 3 к Color, компилятор позволит вам сделать это. Если вы попытаетесь инициализировать переменную x простым 3 без приведения, вы получите диагностику.

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

00
01
10
11

Таким образом, значение 3 все еще находится в диапазоне, поэтому код действителен. Если бы вы произвели 4, то полученное значение было бы не указано стандартом C ++.

На практике реализация должна выбирать базовый целочисленный тип для перечисления. Наименьший тип, который он может выбрать, - char, но он по-прежнему способен сохранять значения в диапазоне вплоть до 127. Но, как уже упоминалось, компилятору не требуется преобразовывать 4 в значение 4, поскольку оно выходит за пределы диапазона перечисления.


Я полагаю, что я должен опубликовать некоторые объяснения различий между "базовым типом" и "диапазоном значений перечисления". Диапазон значений для любого типа является наименьшим и наибольшим значением этого типа. Базовый тип перечисления должен быть в состоянии хранить значение любого перечислителя (конечно) - и два перечисления, которые имеют один и тот же базовый тип, совместимы с компоновкой (это обеспечивает некоторую гибкость в случае несоответствия типов).

Таким образом, хотя базовый тип предназначен для исправления представления объекта (выравнивание и размер), значения перечисления определяются следующим образом в 7.2/6

Для перечисления, где e min - наименьший перечислитель, а e max - наибольший, значения перечисления являются значениями базового типа в диапазоне b min до b max , где b min и b max являются, соответственно, наименьшим и наибольшим значениями наименьшего битового поля, которое может магазин e min и e max . Можно определить перечисление, значения которого не определены ни одним из перечислителей.

[Сноска. На машине с двумя комплементами b max - это наименьшее значение, большее или равное max (abs( e min ) − 1 ,abs( e max )) формы 2 * 1 055 * M * * -1 тысячу пятьдесят шесть; b min равно нулю, если e min неотрицательно и −( b min +1) в противном случае.]

1 голос
/ 29 августа 2009

Color(3) - это приведение с той же семантикой, что и (Color)3, это не конструктор. Обратите внимание, что вы также можете использовать static_cast<Color>(3) для того же преобразования, но вы не можете использовать Color x(3).

0 голосов
/ 29 августа 2009

И стандарты C, и C ++ вводят в заблуждение по поводу перечислений. Оба настаивают на том, что перечисления являются «различными типами», но затем оба рассматривают их как основной интегральный тип. C ++ даже ссылается на курсивный термин «базовый тип», который определяется только при введении wchar_t.

Таким образом, типы wchar_t и enum являются "различными", но просто отображаются на базовый интегральный тип, выбранный реализацией, и это, несомненно, связано с необходимостью совместимости с историческим enum, который определенно был просто int.

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

0 голосов
/ 29 августа 2009

Enum в C ++ - это больше набор именованных целочисленных констант, чем истинный тип, с точки зрения проверки во время компиляции. Тем не менее, стандарт C ++ имеет это, чтобы сказать [dcl.enum]:

9 Выражение арифметического или перечислимого типа может быть преобразовано в Тип перечисления явно. Значение не изменяется, если оно находится в диапазон значений перечисления типа перечисления; в противном случае итоговое значение перечисления не указано.

«Не определено» немного лучше, чем обычное «неопределенное поведение».

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