1. Item 10. 범위 없는 enum 보다
범위 있는 enum을 선호하라
Effective Modern C++ 스터디
이데아 게임즈 손진화
2. • enum Color { black, white, red }
- C++ 98부터 존재
- 범위 없는(unscoped) enum 이라고 불림
• enum class Color { black, white, red }
- C++ 11 에서 추가됨
- 범위 있는(scoped) enum 이라고 불림
- enum 클래스라고도 불린다
3. 차이점1. 범위
• enum Color { black, white, red }
auto white = false; // error!
• enum class Color { black, white, red }
auto white = false; // ok
Color c = white; // error!
Color c = Color::white; // ok
auto c = Color::white; // ok
4. 차이점1. 범위
=> 범위 있는 enum은 이름공간 (namespace)
의 오염을 줄여주니 적극적으로 사용하도록 하
자
5. 차이점2. 타입 변환
• enum Color { black, white, red }
std::vector<std::size_t> primeFactors
(std::size_t x);
Color c = red;
…
if ( c < 14.5) {
auto factors = primeFactors(c);
…
} // ok
6. 차이점2. 타입 변환
• enum class Color { black, white, red }
std::vector<std::size_t> primeFactors
(std::size_t x);
Color c = red;
…
if ( c < 14.5) {
auto factors = primeFactors(c);
…
} // error!
7. 차이점2. 타입 변환
enum class Color { black, white, red }
…
if ( static_cast<double>(c) < 14.5) {
auto factors = primeFactors(
static_cast<std::size_t>(c));
…
} // ok
8. 차이점2. 타입 변환
=> 범위 있는 enum은 암묵적 타입변환이 되지
않으니 적극적으로 사용하도록 하자
=> 그런데 약간 귀찮긴 하다…
9. 차이점2. 타입 변환
using UserInfo = std::tuple<std::string,
std::string,
std::size_t>;
UserInfo uInfo;
…
auto val = std::get<1>(uInfo);
10. 차이점2. 타입 변환
enum UserInfoFields {uiName,
uiEmail,
uiReputation};
auto val = std::get<uiEmail>(uInfo);
// ok
11. 차이점2. 타입 변환
enum class UserInfoFields {uiName,
uiEmail,
uiReputation};
auto val = std::get<
static_cast<std::size_t>(uiEmail)>(uInfo);
// ok
=> 템플릿 함수로 변환하려면?
12. 차이점2. 타입 변환
template<typename E>
constexpr typename std::underlying_type<E>::type
toUType(E enumerator) noexcept
{
return
static_cast<typename
std::underlying_type<E>::type>(enumerator);
}
13. 차이점2. 타입 변환
template<typename E>
constexpr std::underlying_type_t<E>
toUType(E enumerator) noexcept
{
return
static_cast<
std::underlying_type_t<E>>(enumerator);
}
// C++ 14
14. 차이점2. 타입 변환
template<typename E>
constexpr auto
toUType(E enumerator) noexcept
{
return
static_cast<
std::underlying_type_t<E>>(enumerator);
}
auto val = std::get<
toUtype(UserInfoField::uiEmail)>(uInfo);
// ok, C++ 14
15. 차이점3. 전방 선언(forward declaration)
바탕 형식 (underlying type) 이란 열거형 상수
가 프로그램 안에서 실제로 저장되는 정수 형식
을 말합니다.
표준에 따르면 열거형의 바탕 형식은 구현(즉
컴파일러)이 결정합니다.
열거형에서 가장 큰 상수를 담기에 충분한 크기
의 정수 형식이기만 하면 어떤 것이라도 상관이
없습니다.
16. enum Color { black, white, red };
-> 바탕형식 : char
enum Status { …
indeterminate = 0xffffffff};
-> 바탕형식 : char 이상의 정수형
차이점3. 전방 선언(forward declaration)
17. • 범위 없는 enum
- 정의에 따라 컴파일 시 타입이 결정됨
- 정의가 바뀌면 컴파일 다시 해야 함
- 전방 선언 허용하지 않음
enum Color; // error!
enum Status: std::uint32_t; // ok (C++ 11)
차이점3. 전방 선언(forward declaration)
18. • 범위 있는 enum
- 기본 바탕형식은 int로 정해져 있다
- 전방 선언 허용
- 정의가 바뀌어도 컴파일 안 해도 됨
enum class Status; // ok, 바탕형식 int
enum class Status: std::uint32_t; // ok
차이점3. 전방 선언(forward declaration)