항목 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 UPtrMapSS = std::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_t = std::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
'C++11,14 (modern C++)' 카테고리의 다른 글
stl : map 과 array 성능비교. (2) | 2016.06.09 |
---|---|
effective modern c++: 멤버 함수 사용 제한을 delete 키워드로 하는 것이 낫다. (2) | 2016.02.11 |
effective modern c++: noexcept 선언 (0) | 2016.02.05 |
effective modern c++: 명시적 형식 선언보다 auto 를 선호 하라. (3) | 2016.02.01 |
C++11 사용 하는 방법 (0) | 2014.09.17 |