템플릿 클래스의 인자 연역은 가끔 퍼즐을 푸는 것 같은 느낌을 받을 때가 있다. 처음 본격적으로 템플릿 클래스를 작성했을 때 lvalue 참조가 넘어가는 것을 모르고 며칠을 낑낑댄 적이 있었다. 그래서 타입의 한정자를 제거하기 위해 std::decay_t<>를 즐겨 사용했다. 그래도 잘 안될 때면 또 다른 템플릿 클래스를 만들어 몸체가 되는 클래스로 유도했다. 허나 이제 연역 가이드의 힘을 빌리면 그런 것을 아주 쉽게 해결할 수 있다.
template<typename T>
struct List {
template<typename ITER>
List( ITER&& begin, ITER&& end ) :
_list{ begin, end }
{}
List( std::initializer_list<T>&& v ) :
_list{ v }
{}
private:
std::list<T> _list;
};
// ITER 템플릿 인자를 이용하여 List 템플릿 클래스를 구체화시킬 수 있도록 안내해준다
template<typename ITER>
List( ITER&&, ITER&& ) -> List<std::iter_value_t<ITER>>;
...
std::vector v{ 1, 2, 3, 4 };
List list{ std::cbegin(v), std::cend(v) };
위 코드의 핵심은 반복자에서 List의 원소 형식을 얻어내는 것이다. 연역 가이드가 있으면 ITER 형식으로부터 T를 얻어내는 방법을 유도해줄 수 있다. 템플릿 클래스의 활용도가 높아진다.
아래 코드는 연역 가이드 없이 SFINAE 만을 이용해서 작성했다.
template<typename T, typename Enabled = void>
struct List;
template<typename T>
struct List<T, std::enable_if_t<std::_Is_iterator<T>::value>> {
List( T&& begin, T&& end ) :
_list{ begin, end }
{}
private:
std::list<std::iter_value_t<T>> _list;
};
template<typename T>
struct List<T, std::enable_if_t<std::is_trivial_v<T>>> {
List( std::initializer_list<T>&& v ) :
_list{ v }
{}
private:
std::list<T> _list;
};
...
std::vector v{ 1,2,3,4 };
List<decltype(std::cbegin(v))> list0{ std::cbegin( v ), std::cend( v ) };
List<decltype(v)::value_type> list1{ 1,2,3,4 };
'코드' 카테고리의 다른 글
하노이의 탑 (0) | 2021.08.04 |
---|---|
터렛 (0) | 2021.08.03 |
GPUView를 위한 log.cmd가 실행되지 않을 때 (0) | 2021.05.13 |
Game Server Performance on Tom Clancy's The Division 2 (0) | 2021.04.20 |
std::tuple<Ts...> ➔ std::tuple<U<Ts>...> (0) | 2021.03.25 |