반응형



기존 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



반응형

+ Recent posts