[EMC++] Item 9. typedef보다 alias declaration을 선호해라
Item 9. typedef보다 alias declaration을 선호해라
STL 컨테이너와 스마트 포인터들을 사용하다보면 std::unique_ptr<std::unordered_map<std::string, std::string>>
처럼 그냥 입력하기에는 타입이 너무 길다고 느껴질 수 있다.
typedef
C++98에서는 typedef
를 사용해서 타입의 별칭을 정해줄 수 있다.
typedef std::unique_ptr<std::unordered_map<std::string, std::string>> UPtrMapSS;
alias declaration
C++11부터는 typedef
대신 별칭 선언(alias declaration)을 사용한다.
alias declaration은 using
키워드를 사용하는데 C++을 사용해본 사람이면 using
키워드가 아주 익숙할 수 있다.
C++11 이전에는 using
키워드를 특정 namespace에 접근하기 위해 사용하는 ::
(범위 연산자)를 생략하는 목적으로 사용하고 있었기 때문이다.
using namespace std;
,using std::cout;
등등
하지만 C++11부터 using
키워드에는 alias declaration 기능이 추가되었다.
using UPtrMapSS = std::unique_ptr<std::unordered_map<std::string, std::string>>;
alias declaration의 장점
typedef
나 alias declaration이나 하는 일은 동일하다.
하지만 alias declaration의 다음과 같은 장점을 가지고 있다.
코드 가독성이 좋음
함수 포인터가 관여하는 타입을 다룰 때는 alias declaration이 확실히 가독성이 좋다.
// FP는 int와 const std::string&을 매개변수로 하는 함수 포인터
typedef void (*FP)(int, const std::string&);
// 위와 같은 의미
using FP = void (*)(int, const std::string&);
템플릿에 사용할 수 있음
typedef
는 템플릿화할 수 없지만 alias declaration은 템플릿화할 수 있다.
템플릿화된 alias declaration은 별칭 템플릿(alias templates)이라 불린다.
// MyAlloc이라는 custom allocator를 사용하는 linked list의 별칭 선언
template <typename T>
using MyAllocList = std::list<T, MyAlloc<T>>;
MyAllocList<Widget> lw;
위와 같은 alias templates를 typedef
를 사용해 구현하려면 struct
를 이용한 복잡한 편법을 사용해야 한다.
template <typename T>
struct MyAllocList {
typedef std::list<T, MyAlloc<T>> type;
};
MyAllocList<Widget>::type list;
나아가 typedef
와 struct
를 사용해 편법으로 구현한 alias templates을 클래스 템플릿의 멤버 변수 타입으로 사용한다면 다음과 같다.
template <typename T>
struct MyAllocList {
typedef std::list<T, MyAlloc<T>> type;
};
template <typename T>
class Widget {
private:
typename MyAllocList<T>::type list;
}
MyAllocList<T>::type
은 템플릿 매개변수에 의존하는 타입이므로 이를 컴파일러가 알 수 있게 typename
키워드를 써줘야 한다.
하지만 alias declaration을 사용하면 번거롭게 typename
, ::type
을 붙일 필요가 없다.
template <typename T>
using MyAllocList = std::list<T, MyAlloc<T>>;
template <typename T>
class Widget {
private:
MyAllocList<T> list;
}
타입 특성(type trait)
TMP(Template Meta Programming)에서는 템플릿 타입의 매개변수를 받아서 적절하게 변경해야 하는 경우가 있다.
ex) 어떤 타입
T
가 주어졌을 때,T
에 담긴 임의의const
나 참조 한정사(&
,&&
)를 제거해야 하는 경우
C++11에서는 이런 종류의 타입 변환을 지원하는 도구를 제공한다.
이를 타입 특성(type trait)라고 하며 <type_traits>
헤더 안에 템플릿으로 구현되어 있다.
std::remove_const<T>::type // const T를 T로 변환
std::remove_reference<T>::type // T&나 T&&를 T로 변환
std::add_lvalue_reference<T>::type // T를 T&로 변환
문제는 C++11에서는 type trait를 typedef
를 사용해서 구현했다는 것이다.
앞서 말했던 것처럼 typedef
와 struct
를 사용해서 alias templates을 구현하면 typename
키워드를 붙여야하는 번거로움이 발생한다.
alias declaration을 사용한 type trait
C++14에서는 alias declaration을 사용해서 type trait를 구현하였다.
std::remove_const<T> // const T를 T로 변환
std::remove_reference<T> // T&나 T&&를 T로 변환
std::add_lvalue_reference<T> // T를 T&로 변환
만약 C++11을 사용하고 있더라도 직접 alias declaration을 통해 C++14 방식의 type trait를 사용할 수 있다.
template <class T>
using remove_const<T> = typename remove_const<T>::type;
template <class T>
using remove_reference<T> = typename remove_reference<T>::type;
template <class T>
using add_lvalue_reference<T> = typename add_lvalue_reference<T>::type;