본문 바로가기
코드

연역 가이드

by ehei 2021. 5. 22.

템플릿 클래스의 인자 연역은 가끔 퍼즐을 푸는 것 같은 느낌을 받을 때가 있다. 처음 본격적으로 템플릿 클래스를 작성했을 때 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