치춘짱베리굿나이스

[Rank 5] ft_containers - std::iterator_traits 본문

42/42s Cursus

[Rank 5] ft_containers - std::iterator_traits

치춘 2023. 1. 11. 22:57

std::iterator_traits

namespace ft {
template <class Iter>
struct iterator_traits {
    // template로 가져온 클래스에서의 :: 값은 typename으로 가져와야 한다
    typedef typename Iter::difference_type difference_type;
    typedef typename Iter::value_type value_type;
    typedef typename Iter::pointer pointer;
    typedef typename Iter::reference reference;
    typedef typename Iter::iterator_category iterator_category; // iterator의 특성
};

뭐하는 친구인가요

반복자 특질

  • 어떠한 알고리즘이든 컨테이너에서 동작할 때 이터레이터 (반복자) 를 사용하는데, 이때 반복자의 성질을 설명해주기 위한 구조체이다
    • 알고리즘은 인자로 특정 컨테이너의 반복자를 넘겨받아도 이 반복자가 어떠한 특징을 가지고 있는지 알 수 없다
    • 반복자의 특징을 정의한 구조체를 알고리즘 (또는 로직) 에 넘겨줌으로써 알고리즘이 모든 컨테이너 (임의의 컨테이너) 에 대해 동일하게 동작함을 보장한다고 볼 수 있다
  • 이때 사용할 타입 정보를 담은 구조체가 바로 반복자 특질 (iterator_traits) 이다
  • 사실 각 타입에 대한 별칭을 담고 있을 뿐, 특별한 기능이 있는 것은 아니다
    • Iter::difference_type 을 짧게 difference_type 으로 줄인 느낌

각각에 대한 설명

difference_type

Iterator::difference_type 의 단축어이다

반복자와 반복자 간 간격을 표현한다 (메모리를 얼마만큼 건너뛸 것인지?)

value_type

Iterator::value_type 의 단축어이다

반복자가 가리키는 값의 타입을 나타낸다

pointer

Iterator::pointer 의 단축어이다

반복자가 가리키는 값의 포인터 타입을 나타낸다

reference

Iterator::reference 의 단축어이다

반복자가 가리키는 값의 참조 타입을 나타낸다

iterator_category

Iterator::category 의 단축어이다

반복자의 유형을 나타낸다

  • input_iterator_tag
    • 입력 반복자에 대한 태그
    • 입력만 가능하고, 쓰기가 불가능하므로 읽기 전용 알고리즘에서만 사용가능하다
    • 증가 연산자 (++) 를 통한 일방통행만 가능하다
    • 참조 연산자 (*) 를 통한 값 접근 및 읽어들이기가 가능하다
  • output_iterator_tag
    • 출력 반복자에 대한 태그
    • 입력 반복자와는 반대로 입력이 불가능하여 쓰기 전용 알고리즘에서만 사용 가능하다
    • 증가 연산자 (++) 를 통한 일방통행만 가능하다
    • 참조 연산자 (*) 를 통한 값 접근 및 쓰기가 가능하다
  • forward_iterator_tag
    • 순방향 반복자에 대한 태그
    • 입출력이 모두 가능하지만, 증가 연산자 (++) 를 통한 일방통행만 가능하다
    • 입력 반복자와 출력 반복자를 합친 형태이며, 참조 연산자 (*) 를 이용하여 값 읽기 및 쓰기가 모두 가능하다
  • bidirectional_iterator_tag
    • 양방향 반복자에 대한 태그
    • 양방향 반복자는 순회할 때 전진, 후진이 모두 가능하다
    • 전진은 위의 입출력 반복자와 마찬가지로 증가 연산자 (++) 를 사용하고, 후진은 반대로 감소 연산자 (—-) 를 사용한다
    • 순방향 반복자와 마찬가지로, 값 읽기 및 쓰기가 모두 가능하다
    • 순방향 반복자에 후진 기능이 추가되었다고 생각하면 된다
  • random_access_iterator_tag
    • 랜덤 액세스 반복자 (임의 접근 반복자) 에 대한 태그
    • 랜덤 액세스에 관해서는 후술
    • 첨자 연산자 ([]) 를 이용하여 임의의 원소에 접근 가능하다

포인터에 대한 특수화

template <class T>
struct iterator_traits<T*> { // 포인터 T* 특수화 => 랜덤 액세스 가능
    typedef ptrdiff_t difference_type;
    typedef T value_type;
    typedef T* pointer;
    typedef T& reference;
    typedef std::random_access_iterator_tag iterator_category;
    // 포인터 (배열) 쓸 때는 랜덤액세스이므로 랜덤액세스 반복자 태그 지정
};
  • 템플릿이 포인터 타입일 경우, 랜덤 액세스를 지원하기 위해 멤버 타입을 다르게 정의한다
    • 랜덤 액세스란? 어떠한 값에 접근하기 위해 다른 값들을 맨 앞부터 순차적으로 접근 (순차 액세스) 하는 것이 아니라, 특정 값에 바로 접근하는 방식이다
    • 개포동을 가기 위해 선릉에서 한티 → 도곡 → 구룡 → 개포동을 거치는 것이 순차 액세스
    • 개포동을 가기 위해 선릉에서 개포동으로 순간이동 하는 것이 랜덤 액세스
  • 반복자를 기반으로 작성된 알고리즘을 포인터 값으로도 동작할 수 있도록 특수화한 것이다

difference_type

포인터 주소 간 차이를 나타내는 ptrdiff_t가 들어간다

value_type

포인터가 가리키는 값 T 그 자체의 타입이 들어간다

pointer

템플릿 T의 포인터가 들어간다

reference

템플릿 T의 참조가 들어간다

iterator_category

std::random_access_iterator_tag 를 넣는 이유는, 배열 포인터가 랜덤 액세스 방식으로 접근되기 때문에 이러한 형식으로 반복자를 사용한다는 것을 명시하는 것이다


참고 자료

https://en.cppreference.com/w/cpp/iterator/iterator_traits

http://www.tcpschool.com/cpp/cpp_iterator_category

Comments