두 개의 값을 가진 열거 형 클래스가 있고 값을 받고 다른 값을 반환하는 메서드를 만들고 싶습니다. 또한 형식 안전성을 유지하려고합니다 (따라서 열거 형 대신 열거 형 클래스를 사용하는 이유).
http://www.cplusplus.com/doc/tutorial/other_data_types/ 는 메소드에 대해 언급하지 않았지만 모든 유형의 클래스가 메소드를 가질 수 있다는 인상을 받았습니다.
두 개의 값을 가진 열거 형 클래스가 있고 값을 받고 다른 값을 반환하는 메서드를 만들고 싶습니다. 또한 형식 안전성을 유지하려고합니다 (따라서 열거 형 대신 열거 형 클래스를 사용하는 이유).
http://www.cplusplus.com/doc/tutorial/other_data_types/ 는 메소드에 대해 언급하지 않았지만 모든 유형의 클래스가 메소드를 가질 수 있다는 인상을 받았습니다.
답변:
아니요, 그들은 할 수 없습니다.
나는 것을 이해할 수있는 enum class
C ++ 11의 강력한 형식의 열거에 대한 부분은 당신이 있음을 암시하는 보일 수도 enum
있다 class
너무 특성을하지만 그렇지 않다. 교육받은 추측은 키워드 선택이 범위가 지정된 열거 형을 얻기 위해 C ++ 11 이전에 사용한 패턴에서 영감을 얻은 것입니다.
class Foo {
public:
enum {BAR, BAZ};
};
그러나 그것은 단지 구문입니다. 다시, enum class
하지 않은 것입니다 class
.
union
도 John Doe가 수업을 고려한 것이 아닙니다 . 그러나 멤버 함수를 가질 수 있습니다. 그리고 클래스는 멤버 함수에 필수적이지 않습니다. 유사한 지정자 사용 value
또는 this
같은 뭔가 enum Size { Huge, Mega, Apocalypse; bool operator<(X rhs) const { return *this < rhs; }
(여기 또한 수를 ;
) 그냥 기능을 다른 형태의 많은 의미로 만들 수 있습니다.
"당신이 할 수 없습니다"라는 대답은 기술적으로 정확하지만 다음 아이디어를 사용하여 찾고있는 행동을 달성 할 수 있다고 생각합니다.
나는 당신이 다음과 같은 것을 쓰고 싶다고 상상합니다.
Fruit f = Fruit::Strawberry;
f.IsYellow();
그리고 코드가 다음과 같이 표시되기를 바랐습니다.
enum class Fruit : uint8_t
{
Apple,
Pear,
Banana,
Strawberry,
bool IsYellow() { return this == Banana; }
};
...
그러나 열거 형은 메소드를 가질 수 없으므로 (이것은 위의 맥락에서 아무것도 의미하지 않기 때문에) 물론 작동하지 않습니다.
그러나 비 클래스 열거 형과 해당 유형의 값을 포함하는 단일 멤버 변수를 포함하는 일반 클래스의 아이디어를 사용하면 원하는 구문 / 동작 / 유형 안전성에 매우 근접 할 수 있습니다. 즉 :
class Fruit
{
public:
enum Value : uint8_t
{
Apple,
Pear,
Banana,
Strawberry
};
Fruit() = default;
constexpr Fruit(Value aFruit) : value(aFruit) { }
#if Enable switch(fruit) use case:
operator Value() const { return value; } // Allow switch and comparisons.
// note: Putting constexpr here causes
// clang to stop warning on incomplete
// case handling.
explicit operator bool() = delete; // Prevent usage: if(fruit)
#else
constexpr bool operator==(Fruit a) const { return value == a.value; }
constexpr bool operator!=(Fruit a) const { return value != a.value; }
#endif
constexpr bool IsYellow() const { return value == Banana; }
private:
Value value;
};
이제 당신은 쓸 수 있습니다 :
Fruit f = Fruit::Strawberry;
f.IsYellow();
그리고 컴파일러는 다음과 같은 것을 방지합니다.
Fruit f = 1; // Compile time error.
다음과 같은 메소드를 쉽게 추가 할 수 있습니다.
Fruit f("Apple");
과
f.ToString();
지원 될 수 있습니다.
제목 대신 질문에 대한 설명에 집중하면 가능한 대답은
struct LowLevelMouseEvent {
enum Enum {
mouse_event_uninitialized = -2000000000, // generate crash if try to use it uninitialized.
mouse_event_unknown = 0,
mouse_event_unimplemented,
mouse_event_unnecessary,
mouse_event_move,
mouse_event_left_down,
mouse_event_left_up,
mouse_event_right_down,
mouse_event_right_up,
mouse_event_middle_down,
mouse_event_middle_up,
mouse_event_wheel
};
static const char* ToStr (const type::LowLevelMouseEvent::Enum& event)
{
switch (event) {
case mouse_event_unknown: return "unknown";
case mouse_event_unimplemented: return "unimplemented";
case mouse_event_unnecessary: return "unnecessary";
case mouse_event_move: return "move";
case mouse_event_left_down: return "left down";
case mouse_event_left_up: return "left up";
case mouse_event_right_down: return "right down";
case mouse_event_right_up: return "right up";
case mouse_event_middle_down: return "middle down";
case mouse_event_middle_up: return "middle up";
case mouse_event_wheel: return "wheel";
default:
Assert (false);
break;
}
return "";
}
};
다른 답변 에서 언급했듯이 아닙니다. 심지어 enum class
수업이 아닙니다.
일반적으로 필요 방법이하는 enum
그것이 아니다 이유의 결과를 정기적으로 (단지 증가) 열거하지만, 어떤 값의 비트 정의의 마스크 또는 다른 비트 산술 연산을 필요로하는 :
enum class Flags : unsigned char {
Flag1 = 0x01 , // Bit #0
Flag2 = 0x02 , // Bit #1
Flag3 = 0x04 , // Bit #3
// aso ...
}
// Sets both lower bits
unsigned char flags = (unsigned char)(Flags::Flag1 | Flags::Flag2);
// Set Flag3
flags |= Flags::Flag3;
// Reset Flag2
flags &= ~Flags::Flag2;
분명히 비트 마스크 값 또는 비트 인덱스 구동 동작에 의해 단일 / 그룹의 비트를 재설정 / 설정하기 위해 필요한 동작을 캡슐화하는 것은 그러한 '플래그'세트의 조작에 유용 할 것이다.
그만큼 C ++ 11 struct
/ class
specification 은 액세스를 위해 열거 형 값의 범위를 더 잘 지원합니다. 그 이상도 이하도 아닌!
방법은 제한 나갈 열거하는 방법 (클래스) 선언 할 수 없습니다 입니다을 중 하나를 사용합니다 std::bitset
(래퍼 클래스), 또는 비트 필드를union
.
union
비트 필드 공용체 에는 메소드 가 있을 수 있습니다 ( 제한 사항 은 여기 참조 ).
비트 마스크 값 (위 그림 참조)을 해당 비트 인덱스로 변환하는 방법에 대한 샘플이 std::bitset
있습니다. BitIndexConverter.hpp
나는 이것이 '플래그'디 시즌 기반의 가독성을 향상시키는 데 매우 유용하다는 것을 알았 습니다. 알고리즘.
이 꽤 호환 기능 코드 것을 의미 다시 작성할 필요없이 클래스에 열거를 리팩토링하는 (§) 을 효과적으로 수행 할 수 있습니다 당신이 너무 많이 편집없이 할 것을 요청했다 무엇을.
(§) ElementW가 주석에서 지적한 것처럼 type_traits 종속 코드는 작동하지 않습니다. 예를 들어 자동을 사용할 수 없습니다. 그런 것들을 처리하는 방법이있을 수 있지만 결국에는 열거 형을 클래스로 변환합니다. 그리고 항상 C ++을 파괴하는 것은 실수입니다
enum struct
및 enum class
사양은 그래서이의 일부를 범위 지정에 대한 있습니다.
원래 열거 형은 예를 들어 '애완 동물'입니다 (이것은 단지 예일뿐입니다!).
enum pet {
fish, cat, dog, bird, rabbit, other
};
(1) 예를 들어 petEnum (예 : 기존 코드에서 숨기도록)으로 수정합니다.
enum petEnum {
fish, cat, dog, bird, rabbit, other
};
(2) 그 아래에 새로운 클래스 선언을 추가하십시오 (원래 열거 형으로 명명 됨)
class pet {
private:
petEnum value;
pet() {}
public:
pet(const petEnum& v) : value{v} {} //not explicit here.
operator petEnum() const { return value; }
pet& operator=(petEnum v) { value = v; return *this;}
bool operator==(const petEnum v) const { return value == v; }
bool operator!=(const petEnum v) const { return value != v; }
// operator std::string() const;
};
(3) 이제 애완 동물 반에 원하는 수업 방법을 추가 할 수 있습니다. 예. 문자열 연산자
pet::operator std::string() const {
switch (value) {
case fish: return "fish";
case cat: return "cat";
case dog: return "dog";
case bird: return "bird";
case rabbit: return "rabbit";
case other: return "Wow. How exotic of you!";
}
}
이제 std :: cout ...을 사용할 수 있습니다.
int main() {
pet myPet = rabbit;
if(myPet != fish) {
cout << "No splashing! ";
}
std::cout << "I have a " << std::string(myPet) << std::endl;
return 0;
}
pet
/ 인스턴스 를 얻을 것으로 예상되는 유형 공제와 함께 열거 형 값을 사용하는 경우 대신 템플릿 auto
, 또는 decltype
로 인해 중단 petEnum
됩니다.
모든 요구 사항을 충족 시키지는 못하지만 비회원 연산자를 사용하면 여전히 많은 즐거움을 누릴 수 있습니다. 예를 들면 다음과 같습니다.
#include <iostream>
enum class security_level
{
none, low, medium, high
};
static bool operator!(security_level s) { return s == security_level::none; }
static security_level& operator++(security_level& s)
{
switch(s)
{
case security_level::none: s = security_level::low; break;
case security_level::low: s = security_level::medium; break;
case security_level::medium: s = security_level::high; break;
case security_level::high: break;
}
return s;
}
static std::ostream & operator<<(std::ostream &o, security_level s)
{
switch(s)
{
case security_level::none: return o << "none";
case security_level::low: return o << "low";
case security_level::medium: return o << "medium";
case security_level::high: return o << "high";
}
}
이것은 다음과 같은 코드를 허용합니다
security_level l = security_level::none;
if(!!l) { std::cout << "has a security level: " << l << std::endl; } // not reached
++++l;
if(!!l) { std::cout << "has a security level: " << l << std::endl; } // reached: "medium"