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;

나아가 typedefstruct를 사용해 편법으로 구현한 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를 사용해서 구현했다는 것이다.

앞서 말했던 것처럼 typedefstruct를 사용해서 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;


카테고리:

업데이트: