기존 typedef 로는 템플릿 인자는 template 을 허용하지 못했다
template<typename T>
typedef std::vector<T> g1; //이거 에러,
에러명
/*
오류 C2823 형식 정의 템플릿이(가) 잘못되었습니다. Project1
*/
//그런데 using 을 다음처럼 사용해 템플릿 인수를 받아 다시 정의하는게 가능하다
template<typename T>
using ddd111 = std::vector<T>;
int main()
{
ddd111<int> d1;
d1.push_back(2);
..
}
이렇게 쓸대는 전역 변수로 타입을 선언해야 한다
참고 :
함수 포인터 또한 템플릿 인자를 받아 다시 정의 하는게 가능하다
http://blog.naver.com/bluerein_/220563677309
http://spikez.tistory.com/271
항목 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;
};
템플릿 메타 프로그래밍은 결국 현재까지 개발된 코드에서 문제 없는가도 중요하지만,
앞으로 개발될 새로운 코드에서도 적용 가능한가도 매우 중요하죠..
여기서 잠깐, 또 한가지 주의점이 있습니다.
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
'프로그래밍(Programming) > c++, 11, 14 , 17, 20' 카테고리의 다른 글
연산자 오버로딩 함수를 상속 받는 방법 using (0) | 2016.07.04 |
---|---|
상속생성자(Inheriting Constructor) (0) | 2016.07.04 |
[C++] final 키워드( 선언시, 상속제어 등 ) sealed 한정자 (1) | 2016.07.04 |
[C++11] default 키워드와 delete 키워드 (1) | 2016.07.04 |
리눅스 커널모드 (0) | 2016.06.24 |