반응형

항목 9 : typedef 보다는 별칭(using) 을 선호하라.

 

 

STL 컨테이너들을 사용하는 것이 바람직하다. 이건 아마 c++을 사용하는 사람들은 동의 하리라 생각합니다.

std::unique_ptr의 사용 역시 바람직하다는 점에 대해서도 동의 할것 같구요.(저도 동의합니다.)

 

하지만, "std::unique_ptr<unordered_map<std::string, std::string>>" 을 여러번 타이핑하는 것은 하고 싶지 않죠( 120% 공감)

 

이럴때 typedef 를 사용합니다.

typedef std::unique_ptr<unordered_map<std::string, std::string>> UPtrMapSS;

 

C++98 에서 사용하던 방식이죠.

 

C++11에서는 별칭선언(alias declaration) 을 제공합니다.

 

using UPtrMapSSstd::unique_ptr<unordered_map<std::string, std::string>>;

 

 

이 둘의 차이가 있을까요?

 

그전에 한가지!!! (사실 이것 하나만 보더라도 흥미롭습니다.)

 

typedef void(*FP)(int , const std::string&);

 

using FP = void (*)(int, const std::string&);

 

둘 모두 같은 의미입니다. 함수 포인터를 type으로 선언한것인데요.

눈으로 보기에는 using으로 선언한 것이 더 편하고 명확해 보입니다.(물론 함수포인터 선언에 한해서만 봤을때죠.)

 

 

본격적으로 using을 선호해야 하는 이유에 대해서 다룹니다.

 

첫번째 typedef는 template 화 할 수 없습니다. using은 template화 할수 있습니다.

 

template<typename T>

using MyAllocList = std::list<T, MyAlloc<T>>;

MyAllocList<Widget> wg;

 

 

 

typedef를 사용할 경우,

 

template<typename T>

struct MyAllocList {

  typename std::list<T, MyAlloc<T>> type;

};

 

MyAllocList<Widget>::type wg;

 

 

이를 활용하는 template class를 만든다고 합시다.

 

template <typename T>

class Widget {

 private:

   typename MyAllocList<T>::type list;

};

 

C++의 규칙중에는 의존적인 형식(dependent type)의 이름 앞에 반드시 typename을 붙여야 합니다.

 

MyAllocList<T>::type은 템플릿 형식 매개변수 T에 의존적인 형식입니다.

따라서 typename을 붙여야 하며, 또 ::type역시 꼭 필요합니다.

 

보다시피 typedef를 사용하였을때 만들어야 하는 코드를 보면 "어떻게든 되게 만드는" 코드 처럼 보입니다.

 

using은 이런 점들을 보완해서 template을 좀더 자연스럽게 사용할 수 있도록 제공합니다.

template<typename T>

using MyAllocList = std::list<T, MyAlloc<T>>;

template <typename T>

class Widget{

 private:

  MyAllocList<T> list;

}

 

그리고 다음 사항까지도 고려해야합니다.

이 경우 MyAllocList<T>::type은 데이타 타입이 아니라 변수 type이 됩니다.

따라서 반드시 typename을 사용해야 합니다.

 

 

더보기

<검토 필요>

class Wine {...};

 

template <>

class MyAllocList<Wine> {

private:

  enum class WineType {Red, White, Rose};

  WinType type;

};

 

이 경우에  Wine 으로 생성하게 되면 WinType 의 type을 지칭하는 것이 된다.

 

템플릿 메타 프로그래밍은 결국 현재까지 개발된 코드에서 문제 없는가도 중요하지만,

앞으로 개발될 새로운 코드에서도 적용 가능한가도 매우 중요하죠..

 
그때문에 이런 내용들까지도 고려를 해야합니다.

 

 

 

여기서 잠깐, 또 한가지 주의점이 있습니다.

C++11의 STL 에 type과 관련된 template method들이 있습니다.

std::remove_const<T>::type   // const T를 T로 변환

std::remove_reference<T>::type // T& T&&에서 &를 제거

std::add_lvalue_ref<T>::type //T를 T&로 변환

 

이 method들의 구현이 typedef로 구현되어 있기 때문에, ::type이라는 접미사를 붙여야 합니다.

 

이로 인해서 type이라는 이름을 template에서 사용할때는 유의해야합니다.

 

C++14에서는 이를 보완한 멋진 template method들이 있습니다.

 

std::remove_const<T>::type   //C++11

std::remove_const_t<T>      //C++14 에 추가

std::remove_reference<T>::type //C++11

std::remove_reference_t<T>     //C++14에 추가

std::add_lvalue_ref<T>::type //C++11

std::add_lvalue_ref_t<T>     //C++14에 추가

 

아, 그럼 C++11 사용자는 못쓰는건가????

책에 나온 내용을 보면, C++11 컴파일러를 사용하는 사람도 걱정을 할 필요가 없겠더군요.

 

지금까지 살펴본 using을 이용하면 아주 쉽게 처리할 수 있습니다.

 

template <class T>

using remove_const_tstd::remove_const<T>::type;

 

template <class T>

using remove_reference_t = std::remove_reference<T>::type;

 

template <class T>

using add_lvalue_ref_t = std::add_lvalue_ref<T>::type;

 

 

 

[참고] effective modern c++ : 항목 9

 

+ Recent posts