std::unique_ptr<std::unordered_map<std::string, std::string>>
위와 같은 타입이 꽤 많이 선언되고 사용된다고 가정해보자. 저걸 일일이 타이핑 하는것은 시간 낭비일 뿐더러 코드 가독성도 박살나게 된다.
typedef std::unique_ptr<std::unordered_map<std::string, std::string>> UPtrMapSS;
typedef를 사용하면 해결되지만 typedef는 너무 오래된 유물이다.
C++11부터는 별칭 선언이라는게 새로 추가되었다.
using UPtrMapSS = std::unique_ptr<std::unordered_map<std::string, std::string>>;
typedef를 이용한 타입 재정의와 완벽하게 동일한 일을 수행한다.
그럼 왜 굳이 using을 사용해야 하는가?
typedef void (*FP)(int, const std::string&);
using FP = void(*)(int, const std::string&);
둘다 동일하지만 using쪽이 좀더 이해하기 쉽다. 하지만 이것만으로는 using을 사용해야 하는 이유가 되기에는 모자라다.
template<typename T>
using MyAllocList = std::list<T, MyAlloc<T>>; // MyAllockList == std::list<T, MyAlloc<T>>
template<typename T>
struct MyAllocList{
typedef std::list<T, MyAlloc<T>> type; // MyAllocList::type == std::list<T, MyAlloc<T>>
};
템플릿이 추가되면서 상황이 바뀐다. typedef는 템플릿화 할 수 없지만 using은 가능하기 때문이다.
좀 더 번거로워진것 뿐만 아니라 위의 타입들이 또다른 템플릿 안에서 사용되는 경우 typedef로 재정의된 타입은 typename 지정자를 반드시 붙여주어야 하는 번거로운 작업을 또 해야한다.
template<typename T>
class Widget {
private:
typename MyAllocList<T>::type list;
// 만약 T가 int이고 특수화 템플릿 Widget<int>의 멤버 변수 이름이 type이라면?
};
typedef로 재정의된 타입인 MyAllocList는 T에 의존적인 타입인데 C++에서는 이 경우에 앞에 반드시 typename 지정자를 붙여야 하는 규칙이 존재한다. 예를 들어 템플릿 특수화에 의해서 MyAllocList<int>::type이 타입이 아니라 어떤 데이터일수도 있기 때문이다. 그래서 컴파일러에게 타입이라고 명시해주는 것이다.
하지만 using으로 별칭을 선언한 경우는 해당되지 않는다. 똑같이 T에 의존하는 것처럼 보이지만 컴파일러가 MyAllocList<T>에 도달했을 때, 컴파일러는 그게 타입이라는 것을 확신한다. 그래서 typename 지정자가 필요 없고 붙여서도 안된다.
별칭 선언과 관련된 또다른 내용중에 타입 특성(type traits)이라는 것이 있다.
어떤 타입 T에 const 한정자나 참조 한정자를 제거하거나 붙이고 왼값과 오른값을 서로 변환해야 하는 경우에 사용되는 것이다. TMP를 하다보면 마주치게 된다.
타입 특성(type traits)
타입에 대한 상수를 가진 구조체
std::remove_const<T>::type // const T -> T
std::remove_reference<T>::type // T& or T&& -> T
std::add_lvalue_reference<T>::type // T -> T&
...
대략적으로 이런 것이다. type이라는 하나의 인터페이스를 제공해준다. 위에서 봤던 예시와 같지 않은가?
맞다. 구조체 내부에 typedef로 재정의 되어있기 때문에 템플릿에서 사용하게 되면 typename 지정자를 붙여주어야 한다.
std::remove_const<T>::type // C++11
std::remove_const_t // C++14
std::remove_reference<T>::type // C++11
std::remove_reference_t // C++14
std::add_lvalue_reference<T>::type // C++11
std::add_lvalue_reference_t<T> // C++14
여담으로 C++14부터는 using으로 만든 별칭 템플릿도 추가되어있다.
template<typename T>
using remove_const_t = typename remove_const<T>::type;
template<typename T>
using remove_reference_t = typename remove_reference<T>::type;
이런 식으로 되어있다.
◾ typedef는 템플릿화를 지원하지 않지만, 별칭 선언은 지원한다.
◾ 별칭 템플릿에서는 "::type" 접미어를 붙일 필요가 없다. 템플릿 안에서 typedef를 지칭할 때에는 "typename" 접두사를 붙여야 하는 경우가 많다.
◾ C++14는 C++11의 모든 타입 특성 변환에 대한 별칭 템플릿들을 제공한다.
'도서 > Effective Modern C++' 카테고리의 다른 글
[3장] 항목 11 : 정의되지 않은 비공개 함수보다 삭제된 함수를 선호하라 (0) | 2022.12.29 |
---|---|
[3장] 항목 10 : 범위 없는 enum보다 범위 있는 enum을 선호하라 (0) | 2022.12.29 |
[3장] 항목 8 : NULL보다 nullptr을 선호하라 (0) | 2022.12.28 |
[3장] 항목 7 : 객체 생성 시 괄호와 중괄호를 구분하라 (0) | 2022.12.27 |
[2장] 항목 6 : auto가 원치 않은 타입으로 추론될 때에는 명시적 타입의 초기값을 사용하라 (0) | 2022.12.26 |