스토리텔링 개발자

[Effective Modern C++] 9. typedef vs using 본문

Effective C++/Effective Modern C++

[Effective Modern C++] 9. typedef vs using

김디트 2025. 2. 17. 10:54
728x90

항목 9. typedef보다 별칭 선언을 선호하라

 

 

 

typedef와 using
typedef std::unique_ptr<std::unordered_map<std::string, std::string>> UPtrMapSS;
  • C++11에서도 물론 동작하지만
  • C++11에서는 별칭 선언(alias declaration)도 제공한다.
using UPtrMapSS = std::unique_ptr<std::unordered_map<std::string, std::string>>;
  • 하는 일이 완전히 동일한데, 왜 별칭 선언을 선호해야 할까?

 

 

 

함수 포인터
typedef void (*FP)(int, const std::string&);

using FP = void (*)(int, const std::string&);
  • 별칭 선언 쪽의 가독성이 낫다.

 

 

 

템플릿
  • 별칭 템플릿(alias templates)
    • typedef는 템플릿화 할 수 없지만, 별칭 선언은 템플릿화 할 수 있다.
  • C++98에서는 템플릿화된 struct 안에 내포된 typedef들을 활용하는 편법을 동원해야 했지만,
    • C++11에서는 좀 더 직접적으로 표현할 수 있게 되었다.
// using 버전
template<typename T>
using MyAllocList = std::list<T, MyAlloc<T>>

MyAllocList<Widget> lw;

// typedef 버전
template<typename T>
struct MyAllocList
{
    typedef std::list<T, MyAlloc<T>> type;
};

MyAllocList<Widget>::type lw;
  • typedef 버전을 템플릿 안에서 사용하려고 하면
    • template<typename T>
      class Widget
      {
      private:
          typename MyAllocList<T>::type list;
          // typename으로
          // MyAllocList<T>::type은 템플릿 타입 매개변수에 의존적인 타입이라는 걸 명시한다.
          ...
      };
       
    • typedef 앞에 typename을 붙여야 한다.
    • C++은 의존 타입 이름 앞에는 반드시 typename을 붙여야 한다는 규칙이 있다.
    • 그리고, MyAllocList<T>::type은 의존 타입(dependent type)이다.
    • 템플릿 특수화로 인해 MyAllocList<T>::type이 타입 이외의 것을 지칭할 가능성이 있기 때문이다.(EC++ 항목 42 참조)
  • using 버전에서는 불필요하다.
    • template<typename T>
      class Widget
      {
      private:
          MyAllocList<T> list;
          ...
      };
       
    • 여전히 템플릿 매개변수 T에 의존하는 것처럼 보이지만, 컴파일러는 그렇게 생각하지 않는다.
    • 컴파일러가 Widget 템플릿을 처리하는 과정에서 MyAllocList<T>가 쓰인 부분에 도달했을 때,
    • 컴파일러는 그 MyAllocList<T>가 타입의 이름임을 이미 알고 있다.
    • MyAllocList가 타입 템플릿이므로, MyAllocList<T>는 반드시 타입 이름이어야 하기 때문이다.
    • 즉, MyAllocList<T>는 비의존 타입(non-dependent type)이다.

 

 

 

템플릿 메타 프로그래밍(template metaprogramming)과 타입 특성정보(type trait)
  • 템플릿 타입 매개변수를 적당히 가공하여 다른 타입을 만들어내야 하는 경우가 있다.
    • T에 붙은 const를 제거한다거나,
    • T에 참조자(&)를 붙여준다거나.
  • 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&로 변환
  • 헌데, 이 타입 특성정보들은 using이 아니라 typedef의 용법으로 구현되어 있다!
  • C++14에는 별칭 템플릿 버전들이 포함되었다.
// const T를 T로 변환
std::remove_const<T>::type C++11 버전
std::remove_const_t<T> // C++14 버전

// T&나 T&&를 T로 변환
std::remove_reference<T>::type C++11 버전
std::remove_reference_t<T> // C++14 버전

// T를 T&로 변환
std::add_lvalue_reference<T>::type // C++11 버전
std::add_lvalue_reference_t<T> // C++14 버전
  • 만일 C++11 버전을 사용해야 하더라도, 14 버전으로 변경해서 사용하기는 너무나 쉽다.
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;

 

728x90
Comments