- empty class를 이용해서 종류를 구별하는 설계 방법.
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);
}