Який колір встановлений відповідно до стандарту?
Відповідаючи цитатою зі стандартів C ++ 11 та C ++ 14:
[expr.static.cast] / 10
Значення інтегрального або типу перерахування може бути явно перетворене в тип перерахування. Значення є незмінним, якщо вихідне значення знаходиться в межах значень перерахування (7.2). В іншому випадку отримане значення не визначено (і може бути не в цьому діапазоні).
Давайте подивимось діапазон значень перерахування : [dcl.enum] / 7
Для перерахунку, базовий тип якого фіксований, значення перерахування є значеннями базового типу.
Перед CWG 1766 (C ++ 11, C ++ 14)
Тому для data[0] == 100
, отримане значення задається (*), і не визначене поведінка (UB) не бере участь. Більш загально, якщо ви переходите від базового типу до типу перерахування, жодне значення у не data[0]
може призвести до UB для static_cast
.
Після CWG 1766 (C ++ 17)
Див. Дефект CWG 1766 . Абзац p10 [expr.static.cast] p10 був посилений, тому тепер ви можете викликати UB, якщо ви передаєте значення, яке знаходиться за межами репрезентативного діапазону enum, до типу enum. Це все ще не стосується сценарію у питанні, оскільки data[0]
є основним типом перерахування (див. Вище).
Зверніть увагу, що CWG 1766 вважається дефектом у Стандарті, тому прийнято, щоб реалізатори компілятора застосовувались до їхніх режимів компіляції C ++ 11 та C ++ 14.
(*) char
повинен бути принаймні 8 бітовим, але не обов'язково бути unsigned
. Максимальне зберігається значення повинно бути принаймні 127
відповідно до Додатку Е до стандарту C99.
Порівняйте з [expr] / 4
Якщо під час оцінки виразу результат математично не визначений або не знаходиться в діапазоні представлених значень для його типу, поведінка не визначена.
До CWG 1766, тип інтегрального перетворення -> тип перерахування може створювати не визначене значення . Питання полягає в тому, чи може невказане значення бути поза репрезентативними значеннями для його типу? Я вважаю, що відповідь є ні - якби відповідь була так , не було б різниці в гарантіях, які ви отримуєте для операцій з підписаними типами між "ця операція видає не визначене значення" та "ця операція має невизначене поведінку".
Отже, перед РГС 1766, навіть static_cast<Color>(10000)
б НЕ Invoke UB; але після того, як РГС 1766, він робить Invoke UB.
Тепер, switch
заява:
[stmt.switch] / 2
Умова має бути інтегральним, перелічувальним або класовим. [...] Виконуються інтегральні акції.
[конв.пром] / 4
Первозначне значення непокритого типу перерахунку, базовий тип якого фіксований (7.2), може бути перетворений у первісне значення його базового типу. Більше того, якщо інтегральне просування може бути застосоване до його базового типу, первісне значення незафіксованого типу перерахунку, базовий тип якого фіксований, також може бути перетворений у первинну величину промоторованого базового типу.
Примітка: Основним типом обширного перерахунку без опорної бази є int
. Для невизначених перерахунків базовий тип визначається реалізацією, але не повинен бути більшим, ніж int
якщо він int
може містити значення всіх перелічувачів.
Для несхваленого перерахування це призводить нас до / 1
Prvalue цілого типу, крім bool
, char16_t
, char32_t
або wchar_t
чиє число перетворення рангу (4.13) менше , ніж ранг int
може бути перетворений в prvalue типу , int
якщо int
можна уявити все значення типу джерела; в іншому випадку джерело первинного значення може бути перетворене в первісне значення типу unsigned int
.
У випадку незгаданого перерахування ми б тут мали справу з int
s. Для перелічених масштабів ( enum class
і enum struct
) не застосовується цілісне просування. У будь-якому випадку інтегральне просування також не призводить до UB, оскільки збережене значення знаходиться в діапазоні базового типу і в діапазоні int
.
[stmt.switch] / 5
Коли switch
оператор виконується, його стан оцінюється та порівнюється з кожною константою випадку. Якщо одна із констант випадків дорівнює значенню умови, контроль передається оператору, що відповідає відповідній case
мітці. Якщо жодна case
константа не відповідає умові, і якщо є default
мітка, контроль переходить до заяви, позначеної default
міткою.
default
Мітка повинна бути хітом.
Примітка. Можна по-іншому подивитися на оператора порівняння, але він прямо не використовується у згаданому "порівнянні". Насправді, немає жодного натяку на те, що це дозволило б представити UB для перерахованих чи нерозкритих перерахунків у нашому випадку.
Як бонус, стандарт дає будь-які гарантії щодо цього, але з простим перерахуванням?
Незалежно від того, чи enum
є обсяг, чи ні, це не має ніякого значення. Однак це має значення, незалежно від того, чи є базовим тип фіксованим. Повний [decl.enum] / 7:
Для перерахунку, базовий тип якого фіксований, значення перерахування є значеннями базового типу. В іншому випадку для перерахунку, де e min - найменший нумератор, а e max - найбільший, значення перерахування - це значення в діапазоні b min до b max , визначені так: Нехай K
буде 1
представлення комплементу двох та 0
a відображення доповнення або знака. b max - найменше значення, що перевищує або дорівнює max (| e min | - K
, | e max |) і дорівнює 2M - 1 , деM
є невід’ємним цілим числом. b min дорівнює нулю, якщо e min неотрицательно, і - (b max + K
) в іншому випадку.
Давайте подивимось на наступне перерахування:
enum ColorUnfixed /* no fixed underlying type */
{
red = 0x1,
yellow = 0x2
}
Зауважте, що ми не можемо визначити це як перерахований перелік, оскільки всі перераховані перерахунки мають фіксований тип.
На щастя, ColorUnfixed
найменший обчислювач є red = 0x1
, тому max (| e min | - K
, | e max |) дорівнює | e max | у будь-якому випадку, що є yellow = 0x2
. Найменше значення, яке більше або дорівнює 2
, яке дорівнює 2 М - 1 для додатного цілого числа, M
є 3
( 2 2 - 1 ). (Я думаю, що намір полягає в тому, щоб дозволити діапазон в межах 1-бітних кроків.) Звідси випливає, що b max є, 3
а bmin є 0
.
Таким чином, він 100
знаходився б поза межами діапазону ColorUnfixed
, і static_cast
створював би не визначене значення до CWG 1766 та невизначене поведінку після CWG 1766.
char
, тому "значення не змінюється, якщо вихідне значення знаходиться в межах діапазонних значень перерахування (7.2)." застосовується.