enum 클래스에 static_cast 유효하지 않은 경우 어떻게됩니까?


146

이 C ++ 11 코드를 고려하십시오.

enum class Color : char { red = 0x1, yellow = 0x2 }
// ...
char *data = ReadFile();
Color color = static_cast<Color>(data[0]);

data [0]이 실제로 100이라고 가정합니다. 표준에 따라 색상이 어떻게 설정됩니까? 특히 나중에 나중에하면

switch (color) {
    // ... red and yellow cases omitted
    default:
        // handle error
        break;
}

표준이 기본값에 도달한다는 것을 보증합니까? 그렇지 않은 경우 여기에서 오류를 확인하는 가장 적절하고 효율적이며 가장 우아한 방법은 무엇입니까?

편집하다:

보너스로, 표준은 이것과 관련하여 일반 enum을 보장합니까?

답변:


131

표준에 따라 색상이 설정되어 있습니까?

C ++ 11 및 C ++ 14 표준에서 인용 한 답변 :

[expr.static.cast] / 10

정수 또는 열거 유형의 값은 열거 유형으로 명시 적으로 변환 될 수 있습니다. 원래 값이 열거 값 (7.2) 범위 내에 있으면 값이 변경되지 않습니다. 그렇지 않으면 결과 값이 지정되지 않으며 해당 범위에 속하지 않을 수 있습니다.

열거 형 값범위를 찾아 보자 . [dcl.enum] / 7

기본 유형이 고정 된 열거의 경우 열거 값은 기본 유형의 값입니다.

CWG 1766 이전 (C ++ 11, C ++ 14) 따라서 for data[0] == 100에 대해 결과 값이 지정되고 (*) 정의되지 않은 동작 (UB) 이 포함 되지 않습니다 . 더 일반적으로, 기본 유형에서 열거 유형으로 캐스트 할 때 값이에 data[0]대한 UB로 이어질 수 없습니다 static_cast.

CWG 1766 이후 (C ++ 17) CWG 결함 1766을 참조하십시오 . [expr.static.cast] p10 단락이 강화되었으므로 열거 가능한 범위의 열거 형 범위를 벗어난 값을 열거 형 유형으로 캐스팅하면 UB 호출 할 수 있습니다 . data[0]열거 형의 기본 유형이므로 위 의 시나리오에는 적용되지 않습니다 (위 참조).

CWG 1766은 표준에서 결함으로 간주되므로 컴파일러 구현자가 C ++ 11 및 C ++ 14 컴파일 모드에 적용하는 것이 허용됩니다.

(*) char는 너비가 8 비트 이상이어야하지만 필수는 아닙니다 unsigned. 저장 가능한 최대 값 127은 C99 표준의 부록 E 이상이어야 합니다.


[expr] / 4와 비교

표현식을 평가하는 동안 결과가 수학적으로 정의되지 않았거나 해당 유형의 표현 가능한 값 범위에없는 경우 동작이 정의되지 않습니다.

CWG 1766 이전에는 변환 적분 유형-> 열거 유형이 지정되지 않은 값을 생성 할 수 있습니다 . 질문 : 지정되지 않은 값이 해당 유형의 표현 가능한 값을 벗어날 수 있습니까? 대답이 ' 아니요' 라고 답 합니다. 대답이 ' 예' 인 경우 서명 된 유형의 작업에 대해 "이 작업은 지정되지 않은 값을 생성합니다"와 "이 작업은 정의되지 않은 동작을 갖습니다"라는 보장에 차이가 없습니다.

따라서, CWG 1766 이전에도 static_cast<Color>(10000)하지 UB 호출; 그러나 CWG 1766 이후 에는 UB를 호출합니다.


이제, switch진술 :

[stmt. 스위치] / 2

조건은 정수 유형, 열거 유형 또는 클래스 유형이어야합니다. [...] 통합 프로모션이 수행됩니다.

[전환 프롬] / 4

prvalue의 범위가 지정되지 않은 기본 형태 고정 (7.2) 열거 타입의 기본 유형의 prvalue로 전환시킬 수있다. 또한, 기본 승격을 기본 유형에 적용 할 수있는 경우 기본 유형이 고정 된 범위가없는 열거 유형의 prvalue를 승격 된 기본 유형의 prvalue로 변환 할 수도 있습니다.

참고 : enum-base 가 없는 범위가 지정된 열거 형의 기본 유형은 입니다 int. 범위가 지정되지 않은 열거 형의 경우 기본 형식은 구현 정의하지만,보다 큰지지 않습니다 int경우 int모든 열거의 값을 포함 할 수 있습니다.

에 대한 범위가 지정되지 않은 열거 ,이 리드 우리 / 1

이외 정수형의 prvalue bool, char16_t, char32_t, 또는 wchar_t그 정수 변환 계수 (4.13) 이하의 순위보다 int형의 prvalue로 전환 될 수 int있는 경우 int, 소스 타입의 모든 값을 나타낼 수있다; 그렇지 않으면 소스 prvalue를 유형의 prvalue로 변환 할 수 있습니다 unsigned int.

범위가 지정되지 않은 열거 의 경우 int여기에서 처리 합니다. 들어 범위의 열거 ( enum classenum struct), 더 중요한 홍보는 적용되지 않습니다. 어떤 식 으로든, 저장된 값이 기본 유형의 범위와의 범위에 있기 때문에 통합 승격은 UB로 이어지지 않습니다 int.

[stmt. 스위치] / 5

switch명령문이 실행될 때 해당 조건이 평가되고 각 케이스 상수와 비교됩니다. 대소 문자 상수 중 하나가 조건 값과 같으면 일치하는 case레이블 다음에 나오는 명령문으로 제어가 전달됩니다 . case조건에 일치하는 상수가 없고 default레이블 이있는 경우 레이블로 레이블이 지정된 명령문으로 제어가 전달됩니다 default.

default라벨 이 맞아야합니다.

참고 : 비교 연산자를 다시 살펴볼 수 있지만 참조 된 "비교"에서는 명시 적으로 사용되지 않습니다. 실제로, 우리의 경우 범위가 있거나 범위가 지정되지 않은 열거 형에 UB를 도입한다는 힌트는 없습니다.


보너스로, 표준은 이것과 관련하여 일반 enum을 보장합니까?

enum범위가 지정되어 있는지 여부 는 여기서 차이가 없습니다. 그러나 기본 유형이 고정되어 있는지 여부에 차이가 있습니다. 완전한 [decl.enum] / 7은 다음과 같습니다.

기본 유형이 고정 된 열거의 경우 열거 값은 기본 유형의 값입니다. 그렇지 열거위한 전자 작은 열거이고 E 최대가 최대이고, 열거의 값들은 값이 범위에있는 (B)의 하는 최대 다음과 같이 정의 :하자가 K있을 12의 보수 표현과 0A의 하나의 보수 또는 부호 크기 표현. b maxmax (| e min | − K, | e max |) 보다 크거나 같고 2 와 같은 가장 작은 값입니다.M - 1 ,M음이 아닌 정수이다. e min 이 음이 아닌경우 b min 은 0이고,그렇지 않으면 -(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) M - 1 양의 정수가 M있다 3( 2 2 - 1 ). (범위는 1 비트 단위로 범위를 확장하는 것이 목적이라고 생각합니다.) b max is 3bmin is 0입니다.

따라서, 100범위를 벗어난 것 ColorUnfixed, 및이 static_castCWG 후 1,766 1,766 CWG 전에 불특정 값 및 정의되지 않은 동작을 생성한다.


3
기본 유형은 고정되어 있으므로 열거 값의 범위 (§7.2 [dcl.enum] p7)는 "기본 유형의 값"입니다. 100은 확실히의 값 char이므로 "원래 값이 열거 값 (7.2) 범위 내에 있으면 값이 변경되지 않습니다." 적용됩니다.
Casey

2
"UB"가 무엇을 의미하는지 찾아보아야했습니다. ( '정의되지 않은 행동')이 질문은 정의되지 않은 행동의 가능성을 언급하지 않았다. 당신이 그것에 대해 이야기하고있는 것은 나에게 발생하지 않았습니다.
karadoc

2
@karadoc 나는 용어가 처음 나타날 때 링크를 추가했습니다.
dyp

1
이 답변을 좋아하십시오. 너무 빨리 스키밍하는 경우 마지막 문장 "따라서 100이 범위를 벗어납니다 ..."는 기본 유형 사양 (이 경우 char)을 제거하도록 코드를 수정 한 경우에만 적용됩니다. 어쨌든 그게 의미가 있다고 생각합니다.
Eric Seppanen

1
@Ruslan CWG 1766 (또는 그 해상도)은 C ++ 14의 일부 가 아니지만 C ++ 17의 일부라고 생각합니다. C ++ 17 규칙을 사용하더라도 "답변의 추가 텍스트 무효화"의 의미를 이해하지 못합니다. 내 대답의 다른 부분은 주로 "범위의 열거 값"이 expr.static.cast p10이 참조한다는 것입니다.
dyp
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.