C++에서 C#처럼 enum을 쓰는 방법이 있다!

namespace 관련해서 자료를 조사하다가 나온건데...
(참고: C++ namespace(네임스페이스) 코딩 스타일)
 
 

Unreal쪽 자료를 찾아보다가 여길 보니 enum을 C#스타일로 쓰기 위해 namespace를 사용한다는 내용이 나온다. 나도 예전에 생각해봤던건데 진짜로 쓰는 데가 있었구나!

http://udn.epicgames.com/Three/CodingStandard.html


기존의 C++ enum은 다음과 같은 문제가 있었다.
enum Color
{
    Red,
    Green,
    Blue,
... } void Foo(Color color) { switch(color) { case Red: ... break; case Green: ... break; case Blue: ... break; } }

enum이 전역 공간을 돌아다닐 수 있기 때문에 이름 충돌이 일어날 가능성도 높고 - 예를 들면 어디선가 const string Red = "Red"; 같은거 선언하면 모호해진다 - enum보다는 마치 #define된 상수처럼 보이며, 같은 enum소속인지도 알아보기 힘들고, 같은 enum내에 다른 멤버들이 어떤 것이 있는지 알아보기 힘들며, 어디서 사용되는지 유추할 길이 없는 등의 단점이 있다.

약간의 꼼수로는 Color_Red, Color_Green과 같은 이름을 사용하는 방법이 있긴 하다. 나도 지금까지 이렇게 해왔지만 이제 바꿀 예정!


Scoped enum을 사용하는 방법은 다음과 같다.
 
namespace Color
{
    enum Type
    {
        Red,
        Green,
        Blue,
... } } void Foo(Color::Type color) { switch(color) { case Color::Red: ... break; case Color::Green: ... break; case Color::Blue: ... break; } }
이제 각 enum형 상수들이 소속을 가지게 되었다! Visual Studio같은 IDE를 사용한다면 F12등을 누른다거나 Ctrl+Space를 눌러서 Color의 다른 멤버 목록까지 볼 수 있다.

 
다른 방법 - 밑줄 쓰기

다만 변수를 만들 때 ::Type 이라는 것을 붙여 줘야 하는데 - Color::Type 처럼 - 이것도 싫다면 Color_Red, Color_Green 등올 하는 것이 나을 것으로 보인다.

또 밑줄을 사용할 경우, 단독으로 숫자를 사용할 수 있는 장점이 있다. 예를 들면 Keys_1, Keys_2 처럼 사용하는 것도 가능한데, 만약 namespace를 사용한다면 Keys::1, Keys::2 와 같은 방법은 1과 2처럼 숫자로 시작하는 식별자는 컴파일되지 않는다는 면에서 상대적으로 장점으로 볼 수 있다. 뭐 나같은 경우 Keys::D1, Keys::D2로 쓰고 있기는 하다.


 
반응형

중첩된 namespace는 어떻게 써야 하나?

오늘 코딩을 하다가 namespace를 중첩해서 만들어야 할 일이 생겼다. 내가 C#에 영향을 많이 받은지라, 각 namespace의 계층 구조를 만들어서 써보자는 생각을 했다.

그런데 문제가 생겼다. 이거 들여쓰기를 어떻게 해야 할 지 고민된다.

몇 가지 방법을 생각해냈다.

1번

namespace Foo { namespace Bar {
    class ImYourFather
    {
        ...
    }
} }
2번

namespace Foo
{
    namespace Bar
    {
        class INeedACupOfCoffee
        {
            ...
        }
    }
}

3번

namespace Foo
{
namespace Bar
{
class WatchWhereYouShooting
{
    ...
}
}
}



일단 namespace를 제시하는 방법과, namespace와 class의 들여쓰기 방법이 차이가 난다. 따라서 내가 여기에 제시한 것 말고도 여러 변형이 나올 수 있다만, 일단 저 세 개를 후보로 정했다.

1번은 namespace를 옆으로 나열한 것이다. packed 방식이라고 하더라. 들여쓰기는 한 번만 된다.
2번은 namespace마다 들여쓰기를 한 것이다.
3번은 namespace와 class 모두 들여쓰기를 하지 않은 것이다.

예상되는 장점과 단점을 생각해 보자면...

1번
장점
namespace의 계층 구조를 쉽게 파악할 수 있다. 들여쓰기는 한 번만 된다. Visual Studio의 자동 들여쓰기에 의존해도 되므로 편하다. C++은 C#과 달리 namespace를 namespace Foo::Bar {...} 로 선언할 수 없는 것을 가장 유사하게 극복하는 방법이다.

단점
내가 따르는 일반적인 C++ Coding Style을 위반한다. 보통 중괄호는 별개의 라인에 작성해야 한다.




2번
장점
Visual Studio가 알아서 들여쓰기를 해주므로 편하다.

단점
namespace 계층 구조가 깊어질 수록 들여쓰기가 많아진다.




3번
장점
namespace 때문에 들여쓰기가 중첩되는 현상이 없다. 즉, 수평 공간을 낭비하지 않는다.

단점
Visual Studio의 자동 들여쓰기 기능이 있기 때문에 수동으로 왼쪽에 정렬해줘야 하는 불편함이 따른다. 별 것 아니지만 귀찮다.
왠지 namespace만 들여쓰기를 하지 않는게 거슬린다.
계층 구조를 파악하기가 조금 힘들수도 있다.




아... 정말 고민된다!

다른 프로젝트들은 어떻게 하고 있을까?

내가 좋아하는 C#

C#쪽은 대체로 2번 규칙을 따르는 것으로 보인다. 근데 C#은 namespace 지정을 namespace Foo.Bar {...} 이렇게 할 수 있어서 나름 들여쓰기가 절약이 된다.


Google

Google의 경우 3번 규칙과 비슷하다. 다만 중괄호가 같은 라인에 있다.
http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml#Namespaces


Ogre3D

게임 쪽은 어떨까... Ogre3D를 봅시다.
Ogre3D의 경우 2번 규칙과 비슷하다. 중괄호가 namespace와 같은 라인에 있는 경우가 일반적으로 보인다. 별개의 라인에 중괄호가 위치하는 경우도 있기는 하지만 같은 라인에 위치하는 것이 보다 일반적으로 보인다. 좀 더 살펴본 결과 3번 스타일도 사용하는 것으로 확인되었다. 오픈 스스기 때문에 여러 사람이 작업해서 그런건지 스타일도 여러개다.

Ogre3D의 namespace는 계층이 최대 2단계까지만 중첩되기 때문에 어차피 들여쓰기 문제는 없는 것으로 보인다.


WebKit, Mozilla

외국쪽 사정도 비슷한듯... 들여쓰기에 대한 논쟁이 좀 있다.
http://bugreports.qt.nokia.com/browse/QTCREATORBUG-567

살펴보니 WebKit도 3번 규칙을 따른다. http://www.webkit.org/coding/coding-style.html
Mozilla도 3번 규칙을 따른다. https://developer.mozilla.org/En/Mozilla_Coding_Style_Guide


 VS2010에서 namespace indention 안하는 방법
http://stackoverflow.com/questions/3727862/is-there-any-way-to-make-visual-studio-stop-indenting-namespaces


Unreal Engine

사족: C++에서 C#처럼 enum 쓰기
Unreal쪽 자료를 찾아보다가 여길 보니 enum을 C#스타일로 쓰기 위해 namespace를 사용한다는 내용이 나온다. 나도 예전에 생각해봤던건데 진짜로 쓰는 데가 있었구나!

http://udn.epicgames.com/Three/CodingStandard.html


결론

이것 때문에 몇 시간을 다른 사람들은 어떻게 하고 있는지 찾는데 보냈다. 코딩은 언제 하나 ㅠㅠ

대개 3번 유형을 선택하고 있는 것으로 보이고 간혹 2번, 그리고 드물게 1번 스타일을 사용하는 것으로 보인다.

일단은 1번 스타일로 하려고 한다. 중첩된 namespace를 사용하기에는 가장 편리하고 적합한 것으로 보인다. 그리고 namespace 선언으로 발생하는 탭 하나 정도는 괜찮다. 어차피 C#도 보니까 그러더만... 너무 들여쓰기 많아져서 스트레스 받기도 싫고, 들여쓰기 집어넣느라 스트레스 받기 싫다.




반응형

High Cohesion, Low Coupling

진리이다. 항시 기억하자.


예를 들면 인체는 결합도가 높다. 뭔가 하나 수정하려면 주변에 영향을 주는 것이 많아서 굉장히 힘들다. 의사들을 보면 엄청나게 공부를 해야 하고 기억해야 할 것도 많다. 게다가 크고 작은 의료 사고(버그)도 끊이지를 않는다. 환자가 알아서 잘 설명하지 않으면 의사도 어디가 문제인지 모른다.

이번엔 결합도가 아주 낮은 전구와 소켓을 보자. 전구가 나갔으면 전구를 돌려서 슥 뺀다음 새 전구를 끼우면 된다.

반응형

전역 변수를 사용하면 안되는 이유, 함수가 길어지면 안되는 이유가 무엇일까? 인간의 초 단기 기억력은 한 번에 7가지 정보만을 동시에 기억하고 있을 수 있기 때문이다. (관련글: 두뇌이야기 (4) - 워킹메모리를 늘리는 법)


함수를 짧게 만들어야 하는 이유

우리가 코드를 보는 중에 빠르게, 그리고 오래 기억하고 있을 수 있는 사실들은 매우 적다. 예를 들어 지금 지역 변수가 7개를 초과한다면 함수 분석 중 변수의 변화를 더 이상 따라갈 수 없게 된다. 또 if문이 2중, 3중으로 중첩되거나 함수가 길어질 경우에도 그 이전 기억을 모두 붙잡고 있어야만 이해할 수 있기 때문에 이해하기 어려워진다.


전역 변수를 사용하면 안되는 이유

전역 변수의 경우에는 전역 변수가 언제 변하는지 파악하기가 아주 힘들다. 함수 중간에 다른 함수를 호출했는데 내가 쓰고 있던 전역 함수 값이 과연 바뀔까 안바뀔까? 그 밑 함수를 줄줄이 따라가봐야만 알 수 있게 된다.

처음에는 이곳저곳에서 편하게 쓰겠지. 하지만 나중에 가면 전역 변수는 '누구나 건드릴 수 있다'는 점이 문제다. "대체 어떤 자식이 이 변수값을 바꾸는거야" 혹은 "이게 대체 왜 바뀌는거야" 하고 생각하게 될 것이다.





반응형

+ Recent posts