Post List

2015년 1월 4일 일요일

"호환되는 모든 타입"을 받아들이는 데는 멤버 함수 템플릿이 직방!

 스마트 포인터(smart pointer)는 포인터처럼 동작하면서도 포인터가 주지 못하는 상콤한 기능을 덤으로 갖고 있다. auto_ptr, tr1::shared_ptr, STL 컨테이너의 iterator 등이 있다..
 반면 일반 포인터도 스마트 포인터로 대신할 수 없는 특징이 있다. 그 중 하나가 암시적 변환(implicit conversion)을 지원 한다는 점이다. 파생 클래스는 기본 클래스로 변환되고, 비상수 객체에서 상수 객체로의 암시적 변환이 가능하다. 스마트 포인터는 이것이 안된다.

 그럼 어떻게 방법이 없을까 ? 멤버 함수 템플릿(member function template)를 사용하면 된다. 바로 생성자를 만들어내는 템플릿을 사용하는 것이다.

template<typename T>
class SmartPtr {
public:
  template<typename U>
  SmartPtr(const SmartPtr<U>& other) : heldPtr(other.get()) { ... }
  T* get() const { return heldPtr; }
private:
  T* heldPtr;
};

 이런 꼴이 같은 템플릿을 써서 인스턴스화 되지만 타입이 다른 타입의 객체로 부터 원하는 객체를 만들어주는 것을 일반화 복사 생성자(generalized copy constructor)라고 부른다. 그렇다고 해서 기본 클래스로부터 자식 클래스로 변환하거나 int* 를 double* 로 변환하는 등의 원래부터 안되는 것을 되게 해주지는 못한다. 못하게 하는것이 세상의 이치에도 맞는 것이고.

 멤버 함수 템플릿은 복사생성자 뿐 아니라 대입 연산에도 많이 쓰인다.

 * 호환되는 모든 타입을 받아들이는 멤버 함수를 만들려면 멤버 함수 템플릿을 사용합시다.

 * 일반화된 복사 생성 연산과 일반화된 대입 연산을 위해 멤버 템플릿을 선언했다 하더라도, 보통의 복사 생성자와 복사 대입 연산자는 여전히 직접 선언해야 합니다.



댓글 없음:

댓글 쓰기