Iterator 설계시

// iterator별로 다른 tag를 같은 이름으로 사용하도록 셋팅.
template<typename T> class vector_iterator
{
	using iterator_category = random_access_iterator_tag; // empty class.
};

template<typename T> class List_iterator
{
	using iterator_category = bidirectional_iterator_tag;
};

// 배열 타입도 사용하기 위해서.
// 템플릿 특화를 통해서 포인터일경우 다르게 처리.
template<typename T> struct iterator_traits
{
	using iterator_category = typename T::iterator_category;
};
template<typename T> struct iterator_traits<T*>
{
	using iterator_category = std::random_access_iterator_tag;
};

// 같은 이름의 함수이고 인자도 같지만, tag를 다르게 받아서 구별.
template<typename T>
void advance_imp(T& it, std::size_t sz, std::random_access_iterator_tag)
{
	it = it + sz;
}

template<typename T>
void advance_imp(T& it, std::size_t sz, std::input_iterator_tag)
{
	while(sz--)
		++it;
}

// template의 T타입의 iterator_category에 따라서 다른 함수를 호출하도록 셋팅.
template<typename T>
void advance(T& it, std::size_t sz)
{
	// 템플릿 의존적인 타입이므로 typename을 붙여준다.
	advance_imp(it, sz, typename iterator_traits<T>::iterator_category()); 
}

int main()
{
	std::vector<int> v = {1, 2, 3, 4, 5}
	std::list<int> l = {1, 2, 3, 4, 5}
	
	// 이제, 사용된 타입에 따라 해당하는 Iterator를 사용하도록 제공된다.
	auto vbegin = std::begin(v);
	advance(vbegin, 5);

	auto lbegin = std::begin(l);
	advance(lbegin, 5);
}