본문 바로가기

old_Coding/C/C++

[effective C++] 7장. 템플릿과 일반화 프로그래밍-41, 42

 

템플릿. 학생 때나 회사 다닐 때나 참 요물입니다, 이 녀석. 창피한 얘기지만 아직도 잘 모르겠어요. 그래서 공부할 겸, 정보 공유도 할 겸 포스팅으로 스터디 자료를 대체합니다.

 

항목 41: 템플릿 프로그래밍의 천릿길도 암시적 인터페이스와 컴파일 타임 다형성 부터..

이게 도대체 뭔 소리냐.. 뭐 컨셉 자체는 심플합니다. 클래스와 비교를 하는 것이 이해가 빠를테니 클래스를 먼저 보지요.

 

class Widget
{
public:
  Widget();
  virtual ~Widget();
  virtual std::size_t size() const ;
  virtual void normalize() ;
  void swap(Widget& other) ;
  // .. skip
};

예시를 보면, Widget 이라는 클래스는 일종의 타입이며, 이 타입으로 선언/정의된 클래스는 명시되어 있는 인터페이스만 사용이 가능합니다. 이 인터페이스명시적으로 등록되는 것이죠. 그래서 명시적 인터페이스 라고 한답니다. 또, 중간중간 보이는 virtual keyword로 이 클래스는 하위 클래스 들의 함수를 프로그램이 수행되는 런타임 시점에 바인딩이 가능합니다. 이를 런타임에 모양이 바뀐다 하여 런타임 다형성 이라고 한답니다. (햇깔리지마세요. 클래스 이야기입니다.)

 

 

그럼 다시 템플릿으로 돌아오죠. 예제를 들여다 보면 됩니다.

template <typename T>
void doProcessing(T& w)
{
  if (w.size() > 10 && w != someNastyWidget)
  {
    T temp(w) ;
    temp.normalize() ;
    temp.swap(w) ;
  }
}
 
 
의미를 차근차근 읽어보죠. 지금 템플릿 T 는 size/normalize/swap 멤버 함수를 지원해야하고, 복사 생성자 부등비교 연산도 지원해야 합니다. 그리고 컴파일 타임이 돌아가는 템플릿은 이런 것들을 점검합니다. 해당 표현식들이 암시적인 인터페이스를 가지죠. 왜냐면, 실제 타입 T는 A라는 클래스가 될 수도, B라는 클래스가 될 수도 있기 때문입니다.(물론 인스턴스화가 진행되고 나면 어떤 것이 가능한지 밝혀지겠지요) 이를 암시적 인터페이스라고 합니다. 또, 템플릿의 인스턴스화가 컴파일 도중에 일어나기 때문에(컴파일 타임에 모양이 결정됩니다. 물론 여러 개의 인스턴스가 나올 수도 있죠) 컴파일 타임 다형성 이란 성질을 가지게 되었네요.
 
 
책에선 어떤 경우에 구현자가 머리를 쥐어 짜내느냐에 관한 얘기를 했네요 ㅎㅎ. 명시적 인터페이스의 시그니처에 관한 얘기가 있지만, 이 부분은 skip해도 될 것 같습니다. 요점은 유효 표현식 입니다. 뭐 지극히 당연한 얘기지만, 위의 템플릿 예제에서 타입 T는 normailze(), swap(), size() 등의 함수를 지원해야 합니다. 즉, 타입 T가 꼭 지원해야 할 부분들을 상식적으로 생각해 보아도 눈에 보입니다. 그리고, 너무 걱정하지 않아도 될 점은 이 유효 표현식이 정확히 들어맞지 않으면, 코드는 컴파일조차 되지 않기 때문입니다. 이 말은 다시 말하면, 정상적으로 이 조건을 만족하지 않고서 솔루션/바이너리가 배포되는 불상사는 미연에 방지되고 있다는 점입니다.
 
너무 걱정할 필요 없이 막히면 구글링 혹은 서적을 통해 논리적으로 만들어 준 뒤, 작업을 하면 되겠군요!
 
 
 
 
항목 42: typename의 두 가지 의미를 제대로 파악하자.
 
 
typename은 두 가지 역할을 가지고 있답니다. 저도 처음엔 몰랐던 사실! 스콧 아저씨가 주는 일종의 팁이라고 해도 되겠네요. 미소 
 
활용 1) 우리가 이미 알고 있는 활용.
template<class T> class Widget;

template<typename T> class Widget;

두 가지 의미는 완전히 동일하답니다. 뭐, 이건 설명 안하고 넘어가도 되겠죠? 모르시면 우리의 국민 사이트 http://www.winapi.co.kr 방문하셔서 한번 둘러보세요~

 

활용 2) 타입이 모호할 때 이것이 타입이다 알려줄 때의 활용

 
template <typename C>
void Temp(const C& container)
{
  C::const_iterator *x;
}
  위의 예제에서 컴파일러는 어떻게 이해하게 될까요? 우리의 눈으로야 C라는 컨테이너의 iterator type인 C::const_iterator라는 타입의 포인터인 x가 생겨났으리라고 믿고 있겠지요. 그러나!, 이런 논리는 우리에게만 적용되는 것이고 컴파일러는 이를 C라는 클래스 안에 const_iterator라는 변수가 있고 이를 x와 *(곱하기연산)을 하는 것 이구나! 라고 생각할 겁니다. 두 가지 모두 가능성이 있는 이야기지요. 여기서 모호성이 발생합니다. 이런 상황에서 C::const_iterator가 변수가 아니라 타입이다. 라고 지정해 주는 것이 바로 두 번째 typename이 하는 일이랍니다.(처음엔 몰랐어요. 그러나, 좋은 명시인 것 같네요) 위의 예제는 다음과 같이 변합니다.  
 
template <typename C>
void Temp(const C& container)
{
  typename C::const_iterator *x;
}

이제서야 컴파일러는 x라는 변수를 C::const_iterator* 에 맞게 설정할 수 있겠네요. 미소

 

위와 같은 상황의 변수타입을 중첩 의존 타입 이라고 한답니다. C 라는 미지의 타입 내부에 변수/타입/함수 등이 무엇인지 애매한 타입을 말하는데요. 이 경우 typename을 활용하여 컴파일러에게 “이것은 타입이다!” 라고 강하게 어필할 수 있는 도구이죠. 여기까지 typename의 두 번째 활용이었습니다. (책에는 사용하지 말아야 할 경우까지 설명되어 있지만 skip합니다. 논리적으로 생각해보면 당연한 이야기인듯 하니까요)

 

 

 

'old_Coding > C/C++' 카테고리의 다른 글

[C/C++] 문자열 다루기(1) - 초기화  (0) 2010.12.13
[STL::Map] Error occured(*)  (0) 2010.03.18
[C] File I/O  (0) 2010.03.11
[Scrap] Struct SYSTEM_INFO (*)  (0) 2010.01.04
[C++] Function Pointer(3) (Solution)  (0) 2009.12.27