2009.07.30 14:06 책 정리/Modern C++ Design

템플릿 코드를 쓰다 보면 템플릿 파라미터인 T가 어떤 특성을 가지고 있는지 알아야 할 때가 있다.

예를 들자면, swap 을 하려 할 때, POD 형이라면, memcpy 를 이용하여 복사 하고 아닌 경우라면, 생성자 호출에 의한 값 복사를 진행하면 꽤 좋은 성능을 낼 수 있기 때문이다.

이번 장에선 템플릿 파라미터인 T의 특성을 컴파일 타임에 확인하는 테크닉에 대해서 설명한다. 이러한 테크닉의 설명에 앞서 이미 만들어진 라이브러리(Boost.TypeTraits)도 있다는 것을 미리 밝힌다.

2.10.1 포인터 Traits의 구현
쉽게 말해서 포인터 형인지 확인하는 테크닉이다. 코드를 보면 한번에 알 수 있을 테니 코드를 적어 둔다.

직감적으로 아~ 그럴 수도 있겠지만, "나는 사실 클래스 템플릿 특수화가 저렇게 되나?" 하며 C++ Template 책을 꺼내서 찾아 보았다. 이런 .. 클래스 템플릿 특수화는 저런식으로 한다..

타입이 포인터 인지 체크하는 원리를 정리 하자면 이러 하다.

  1. 모든 타입에 대해서 일반 클래스 템플릿인 PointeeTraits가 활성화 되게 한다.
  2. 그 외로 포인터 타입일 경우 PointeeTraits<U*>가 활성화 되게 한다.


함수 템플릿의 특수화로 분기시키는것과 동일하다. 이러한 클래스는 C++ Template Metaprogramming 책에선 "메타 함수" 라고 부르는데 이건 훗날에 정리하기로 한다.

이러한 원리로 레퍼런스인가? 아닌가? 도 체크 할 수 있다. 다음 코드를 보자.

어떻게 바뀌였는지 위 코드와 비교 해보면, "아하!"라고 할 것이다.

이걸 더 응용하면, 멤버 포인터 인가? 를 알 수도 있는데, 이건 5장에 가서 정리하기로 한다.

여담, 클래스 템플릿 부분 특수화에 대해서...
어지간한건 이러한 부분 특수화로 다 찾아 낼 수 있다는 자신감이 든다. 지금까지 배운것으로는 상속가능 여부, 포인터 가능 여부, 레퍼런스 가능 여부, 함수 분기 메카니즘 이다. 이러한 것들은 어찌보면 컴파일 타임 함수로 인식되는데, 이러한 인식이 바로 "메타 함수"라고 불리우게 되었던 것이 아닐까 한다.

2.10.2. 기본 자료형인지 확인하는 테크닉
... 3장의 내용을 맞보기로 설명한 파트인데, 코드는없다. 그러므로 이번 파트는 생략하고, boost.typetraits 로 확인하는 방법을 설명 한다

.....
....

boost.typetraits 에 기본 자료형인지 판별하는건 못찾겠고, is_scalar 가 좋겠다. 사용법은 다음과 같다.

나쁘지 않군. 그런데 이런걸 알아서 어디에 써 먹을려고!? 라는 생각을 했다면, 좋은 통찰력을 지닌 것이다. 그 이야기는 2.10.3에서 다루도록 한다.


2.10.3 인자의 자료형에 대한 최적화 테크닉
지금까지 타입의 특성(trait)을 파악하는 이유가 최적화에 용이하기 때문이라고 말하고 공부했었는데, 정작 어떻게 최적화 시켜야 하는지에 대해서 설명하지 않은게 있었다.

이번 장에서 바로 "최적화 테크닉"을 공부 할 수 있다.

무엇을 어떻게 최적화 하는가?
객체의 복사를 적절한 분기를 통하여, 객체 복사에 대한 오버헤드를 낮추어 최적화 하는 기법이다. 일반적으로 스칼라 값은 값 자체를 복사하여 함수에 전달하는게 효과적이며, 복잡하고 난잡한 객체의 경우, 레퍼런스로 전달하는게 효과적이다.(물론 경우에 따라선 복사 해야 할 때도 있다.) 여기서 주의 해야 할 게 있는데, 참조에 대한 참조는 C++ 문법에서 불법이므로, 이 경우를 잘 처리해 주어야 한다.

그러므로 최적화 알고리즘을 만들어 본다면 다음 구조가 될 것이다.

만약 T가 참조형인 경우, T 형 그대로 사용 한다.
그렇지 않을 경우, 만약 T가 스칼라 값이라면, T형 그대로 사용 한다.
그렇지 않을 경우, T를 T& 으로 사용 한다.

휴, 이렇게 말로만 정리하니까 참 편하다. ㅋㅋ 하지만 이것으로 만족을 못하니 코드를 한번 짜 보자.

휴~ 실제로 출력에는 레퍼런스(&)가 안되어 있지만, 실제로 BreakPoint 를 찍어서 봐보면, T const & 로 되어 있다. ㅋㅋ 아참 boost를 쓴게 너무하다고 생각 할 수 있겠으나, ... 세상 다 그런거 아닌가? 이미 끝내주게 잘 만들어 진게 있는데 끝내주게 써 주지는 못할 망정 다 짜는건 아니지 않는가? ㅋㅋ

2.10.4 한정자 제거하는 테크닉
.. 이런 테크닉이야. 이전에도 했었지 아니한가? 바로 한정자 찾아내기 비스무리한거(포인터 인가? 레퍼런스 인가?) 말이다. 뭐 까먹어도 괜찮다. 워낙 개념이 쉬우니까..

경우에 따라서 한정자(const, volatile)을 지워야 할 때가 있다. 사실 이런 경우 겪어 본적이 없다. 책에선 SmartPtr 구현시 써야 한다고 하지만, 아직은 잘 모르겠으니 패스, 그 원리만 파악해 보자.

자 코드만 보면 쉽게 이해 되니 바로 코드로 넘어 간다.

음 괜찮군 괜찮아. ㅋㅋ

2.10.5 TypeTraits의 사용
이번 장과 2.10.6, 2.10.7은 정리할 게 없다. 왜냐하면 지금까지 했던 이야기를 정리하기 위한 장이기 때문이다. 그래도 읽는 도중에 뇌리에 꽂힌건 다음과 같다.

2.10.5
현재로써 POD를 알기 위해선 수동으로 처리 해야 한다. 로 정리 되지만, boost::is_pod 가 있다. 하지만 컴파일러가 지원해야 한다고, 메뉴얼에 나와 있다.. (이런 ..) 그래도 코드를 한번 만들어 봤다. msvc9와 g++43 으로 컴파일 해봤는데, 둘다 잘 되었다. 괘니 겁 먹었네.

얏호. 그렇군, 내가 알고 싶었던 어느정도의 타입을 체크하는 원리와 어디에 사용하는지 였는데, 이번 장에서 자세히 다루어 주어서 무척 마음에 들었다.

휴~ 이것으로 챕터 2, 테크닉이 끝난다. 챕터 3 가 슬슬 기대 되기도 한다. ㅋㅋ

posted by 농사를 짓는 게임 프로그래머 최익필

댓글을 달아 주세요