성태의 닷넷 이야기
홈 주인
모아 놓은 자료
프로그래밍
질문/답변
사용자 관리
사용자
메뉴
아티클
외부 아티클
유용한 코드
온라인 기능
MathJax 입력기
최근 덧글
[정성태] 아쉽게도, 커뮤니티는 아니고 개인 블로그입니다. ^^
[정성태] 질문이 잘 이해가 안 됩니다. 우선, 해당 소스코드에서 ILis...
[양승조
] var대신 dinamic으로 선언해서 해결은 했습니다. 맞는 해...
[양승조
] 또 막혔습니다. ㅠㅠ var list = props[i].Ge...
[양승조
] 아. 감사합니다. 어제는 안됐던것 같은데....정신을 차려야겠네...
[정성태] "props[i].GetValue(props[i])" 코드에서 ...
[정성태] 저렇게 조각 코드 말고, 실제로 재현이 되는 예제 프로젝트를 압...
[정성태] Modules 창(Ctrl+Shift+U)을 띄워서, 해당 Op...
[정성태] 만드실 수 있습니다. 단지, Unity 엔진 내의 스크립트와 W...
[공진영] 안녕하세요 좋은글 감사합니다. 현재 제가 wpf로 관제 모...
글쓰기
제목
이름
암호
전자우편
HTML
홈페이지
유형
제니퍼 .NET
닷넷
COM 개체 관련
스크립트
VC++
VS.NET IDE
Windows
Team Foundation Server
디버깅 기술
오류 유형
개발 환경 구성
웹
기타
Linux
Java
DDK
Math
Phone
Graphics
사물인터넷
부모글 보이기/감추기
내용
<div style='display: inline'> <h1 style='font-family: Malgun Gothic, Consolas; font-size: 20pt; color: #006699; text-align: center; font-weight: bold'>enum 정의를 C++11의 enum class로 바꿀 때 유의할 사항</h1> <p> 기존 enum의 명확한 단점은 다음의 소스 코드로 알 수 있습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > enum TestMode { OFF, }; enum MyMode { OFF, // Error C2365 'OFF': redefinition; previous definition was 'enumerator' }; </pre> <br /> 이 때문에, 어쩔 수 없이 Prefix를 정의해 함께 사용해야만 했습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > enum TestMode { <span style='color: blue; font-weight: bold'>TM_</span>OFF, }; enum MyMode { <span style='color: blue; font-weight: bold'>MM_</span>OFF, }; </pre> <br /> 윈도우 헤더 파일에 정의된 수많은 enum 타입들의 상수가 왜 타입명을 함께 붙이고 정의하는지,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > // windef.h typedef enum <span style='color: blue; font-weight: bold'>DPI_AWARENESS</span> { <span style='color: blue; font-weight: bold'>DPI_AWARENESS_</span>INVALID = -1, <span style='color: blue; font-weight: bold'>DPI_AWARENESS_</span>UNAWARE = 0, <span style='color: blue; font-weight: bold'>DPI_AWARENESS_</span>SYSTEM_AWARE = 1, <span style='color: blue; font-weight: bold'>DPI_AWARENESS_</span>PER_MONITOR_AWARE = 2 } DPI_AWARENESS; </pre> <br /> 바로 이런 이유 때문이었던 것입니다.<br /> <br /> <hr style='width: 50%' /><br /> <br /> 그러다가, C++11 표준에서 "enum class"가 나와 더 이상 접미사가 필요 없게 되었습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > enum class TestMode { ON, OFF, }; enum class MyMode { ON, OFF }; int main() { MyMode mode1 = MyMode::ON; MyMode mode2 = ON; // 컴파일 오류 } </pre> <br /> 하지만, 그래도 내부적으로는 "#define"과의 충돌을 해결하지 못해 다음과 같은 상황에서는 컴파일 오류가 발생합니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > #define ON 100 enum class MyMode { ON, // Error C2059 syntax error: 'constant' OFF }; </pre> <br /> 물론 이해는 됩니다. "ON"이라는 리터럴 자체를 #define 정의에 의해 모조리 치환하기 때문에 결국 다음과 같이 번역되므로 오류가 발생하는 것이 당연합니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > #define ON 100 enum class MyMode { <span style='color: blue; font-weight: bold'>100</span>, // Error C2059 syntax error: 'constant' OFF }; </pre> <br /> 따라서 기존 헤더 파일에 같은 상수명이 정의되어 있다면 접미사를 붙이거나 명시적으로 #undef으로 해결할 수밖에 없습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > enum class TestMode { TM_ON, OFF, }; enum class MyMode { #undef ON ON, OFF }; </pre> <br /> <hr style='width: 50%' /><br /> <br /> enum class의 또 하나 문제점(?)이 있다면, 형식 안정성으로 인해 기존 enum이 int 타입 연산을 자연스럽게 할 수 있었던 것을 못하게 막는다는 점입니다. 즉, 다음과 같은 식의 비트 플래그 연산들이 enum class 사용 후부터 모두 오류가 발생하게 됩니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > int main() { MyMode mode1 = MyMode::ON; MyMode mode2 = MyMode::OFF; // Error C2676 binary '&': 'MyMode' does not define this operator or a conversion to a type acceptable to the predefined operator if (<span style='color: blue; font-weight: bold'>(mode1 & mode2) == mode2</span>) { } } </pre> <br /> 이 문제를 해결하려면 명시적인 int 형변환을 하거나,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > if (((int)mode1 & (int)mode2) == (int)mode2) </pre> <br /> "(int)" 형변환 따위의 코드 수정 없이 하고 싶다면, 좀 더 우아하게는 다음과 같이 연산자 재정의를 추가하면 됩니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > inline MyMode operator&(MyMode& l, MyMode &r) { return (MyMode)((int)l & (int)r); } inline MyMode operator|(MyMode& l, MyMode& r) { return (MyMode)((int)l | (int)r); } </pre> <br /> 멋스럽게 & 연산자를 추가해봤지만 저런 경우 다음과 같은 식의 상황에서는 컴파일 오류가 발생하므로,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > auto GetFlags() -> MyMode { return mode; } int main() { MyMode mode = MyMode::ON; MyMode mode2 = MyMode::OFF; if ((mode | mode2) == mode2) { mode = MyMode::ON; } char* ptr = nullptr; // Error C2678 binary '&': no operator found which takes a left-hand operand of type 'MyMode' (or there is no acceptable conversion) if (<span style='color: blue; font-weight: bold'>(GetFlags() & mode2)</span> == mode2) { mode = MyMode::ON; } } </pre> <br /> 이 상황을 해결하기 위해 const 등의 좀 더 복잡한 코드를 만들 수도 있지만,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > auto GetFlags() -> const MyMode& { return mode; } inline MyMode operator&(const MyMode& l, MyMode &r) { return (MyMode)((int)l & (int)r); } </pre> <br /> 어차피 enum이 int 범위 내의 값이라는 특성을 감안하면 굳이 const로 만들지 않아도 된다는 점과, 오히려 ref를 받아 변경할 수 있도록 하는 것이 아니라면 애당초 그냥 아무 처리 없이 사용하는 것이 더 나은 선택일 것입니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > inline MyMode operator&(MyMode l, MyMode r) { return (MyMode)((int)l & (int)r); } inline MyMode operator|(MyMode l, MyMode r) { return (MyMode)((int)l | (int)r); } </pre> <br /> (<a target='tab' href='https://www.sysnet.pe.kr/bbs/DownloadAttachment.aspx?fid=1469&boardid=331301885'>첨부 파일은 이 글의 예제 코드를 포함</a>합니다.)<br /> </p><br /> <br /><hr /><span style='color: Maroon'>[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]</span> </div>
첨부파일
스팸 방지용 인증 번호
1230
(왼쪽의 숫자를 입력해야 합니다.)