뭔가 복잡하고 완벽하게 만들려면 좀더 까다롭겠지만,
range-based for loop 또는 std:find 등의 STL algorithm을 이용할 수 있도록 간단하게 만든다면, 아래와 같이 하면 되겠다.
(물론 검증된 것은 아니고, 정말 연습용으로 해 보고 정리하는 것임. 따라서 오류가 있을수도...;;)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | template < typename T> class slist_iterator { public : typedef std::forward_iterator_tag iterator_category; typedef typename slist<T>::value_type value_type; //T typedef typename slist<T>::reference reference; //T& typedef typename slist<T>::pointer pointer; //T* typedef typename slist<T>::difference_type difference_type; //std::ptrdiff_t public : slist_iterator( typename slist<T>::node_ptr p = nullptr) : current_(p) {} ~slist_iterator() = default ; slist_iterator(slist_iterator const &) = default ; slist_iterator& operator=(slist_iterator const &) = default ; bool operator==(slist_iterator const & rhs) const { return rhs.current_ == current_; } bool operator!=(slist_iterator const & rhs) const { return rhs.current_ != current_; } reference operator*() const { return current_->data_; } pointer operator->() const { return ¤t_->data_; } slist_iterator<T>& operator++() { current_ = current_->next_; return * this ; } private : typename slist<T>::node_ptr current_; }; |
template <typename T> class slist는 이미 정의가 되어 있고,
template <typename T> class slist_iterator가 friend로 지정되어 있다.
(또는 slist의 nested class로 구현하여도 되겠다)
처음에는 아래와 같은 type을 노출하지 않았었다.
1 2 3 4 5 | typedef std::forward_iterator_tag iterator_category; typedef typename slist<T>::value_type value_type; //T typedef typename slist<T>::reference reference; //T& typedef typename slist<T>::pointer pointer; //T* typedef typename slist<T>::difference_type difference_type; //std::ptrdiff_t |
그 상태로 range-based for loop은 문제가 없었지만, std::find를 호출 했더니, iterator_category를 지정해야 한다는 에러 메시지가 나와서 추가 해 주었다.
그랬더니 std::iterator_traits 뭐라뭐라 에러가 나는데, 뭐라 하는지 전혀 모르겠더라;;
그래서 혹시나 하는 마음에 value_type, reference를 추가 해 보았으나 동일ㅠㅠ
결국, stackoverflow에서 해답을 찾았다. (오늘 알게 된 사실인데, 해당 글의 const_iterator 구현 부분에서 operator*, operator->의 반환값이 그냥 reference, pointer로 되어 있어, 값을 할당하여도 에러가 발생하지 않는다. 이 부분은 수정이 필요함. 맨 아래 전체 소스 참고.)
위의 네 개의 타입과 iterator_category는 반드시 노출되어야 하고,
iterator_category에 따라 필요한 멤버함수들을 구현 해 주면 된다.
정말 간단하게 구현하는 방법은 std::iterator를 상속하여 구현하는 것인데,
이놈이 C++17에서 없어질 예정이므로, 이후 어떻게 해야 할지는 알아봐야 할듯.
아래는, 허접하지만 const_iterator까지 구현한 전체 소스 (__)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 | #include <iterator> #include <iostream> #include <algorithm> template < typename T> class slist_iterator; template < typename T> class slist_const_iterator; template < typename T> class slist { template < typename T> struct node { T data_; node* next_; node(T const & data, node* node) : data_(data), next_(node) {} }; typedef node<T>* node_ptr; typedef slist_iterator<T> iterator; typedef slist_const_iterator<T> const_iterator; public : typedef T value_type; typedef T& reference; typedef T const & const_reference; typedef T* pointer; typedef T const * const_pointer; typedef std:: ptrdiff_t difference_type; typedef std:: size_t size_type; public : slist() : head_(nullptr) {} ~slist() { node_ptr n = head_; while (n && n->next_) { node_ptr t = n; n = n->next_; delete t; } delete n; } void push_front(T const & data) { head_ = new node<T>(data, head_); } T const & front() const { return head_->data_; } T& front() { return head_->data_; } void pop_front() { node_ptr n = head_; head_ = head_->next_; delete n; } iterator begin() { return iterator(head_); } const_iterator begin() const { return const_iterator(head_); } const_iterator cbegin() const { return const_iterator(head_); } iterator end() { return iterator(); } const_iterator end() const { return const_iterator(); } const_iterator cend() const { return const_iterator(); } private : node_ptr head_; private : friend class slist_iterator<T>; friend class slist_const_iterator<T>; }; template < typename T> class slist_iterator { public : typedef std::forward_iterator_tag iterator_category; typedef typename slist<T>::value_type value_type; typedef typename slist<T>::reference reference; typedef typename slist<T>::pointer pointer; typedef typename slist<T>::difference_type difference_type; public : slist_iterator( typename slist<T>::node_ptr p = nullptr) : current_(p) {} ~slist_iterator() = default ; slist_iterator(slist_iterator const &) = default ; slist_iterator& operator=(slist_iterator const &) = default ; bool operator==(slist_iterator const & rhs) const { return rhs.current_ == current_; } bool operator!=(slist_iterator const & rhs) const { return rhs.current_ != current_; } reference operator*() const { return current_->data_; } pointer operator->() const { return ¤t_->data_; } slist_iterator<T>& operator++() { current_ = current_->next_; return * this ; } private : typename slist<T>::node_ptr current_; }; template < typename T> class slist_const_iterator { public : typedef typename slist<T>::value_type value_type; typedef typename slist<T>::reference reference; typedef typename slist<T>::const_reference const_reference; typedef typename slist<T>::pointer pointer; typedef typename slist<T>::const_pointer const_pointer; typedef typename slist<T>::difference_type difference_type; typedef std::forward_iterator_tag iterator_category; public : slist_const_iterator( typename slist<T>::node_ptr p = nullptr) : current_(p) {} slist_const_iterator(slist_const_iterator const &) = default ; slist_const_iterator(slist_iterator<T> const & rhs) { current_ = rhs.current_; } ~slist_const_iterator() = default ; slist_const_iterator& operator=(slist_const_iterator const &) = default ; bool operator==(slist_const_iterator const & rhs) { return rhs.current_ == current_; } bool operator!=(slist_const_iterator const & rhs) { return rhs.current_ != current_; } slist_const_iterator& operator++() { current_ = current_->next_; return * this ; } const_reference operator*() const { return current_->data_; } const_pointer operator->() const { return ¤t_->data_; } private : typename slist<T>::node_ptr current_; }; int main() { slist< int > list; for ( int i = 0; i < 20; ++i) { list.push_front(i); } for ( int i = 100; i < 120; ++i) { list.push_front(i); } for (auto i : list) { std::cout << i << '\n' ; } auto itr = std::find(list.begin(), list.end(), 100); while (itr != list.end()) { std::cout << *itr << '\n' ; ++itr; } for ( int i = 0; i < 10; ++i) { list.pop_front(); } auto citr = std::find(list.cbegin(), list.cend(), 119); while (citr != list.cend()) { std::cout << *citr << '\n' ; ++citr; } citr = std::find(list.cbegin(), list.cend(), 15); while (citr != list.cend()) { std::cout << *citr << '\n' ; //*citr = 100; //error!!! ++citr; } } |
'프로그래밍 언어' 카테고리의 다른 글
Magic statics since C++11 (0) | 2018.05.29 |
---|---|
C++로 JAVA의 DataInputStream, DataOutputStream 흉내내기 (0) | 2017.09.14 |
CppCon 2014: Herb Sutter "Lock-Free Programming (or, Juggling Razor Blades)" (1) | 2016.07.25 |
Spirit 3.0.0 (Boost?) (0) | 2016.07.11 |
EXCEL에서 특정 column에서 동일한 값을 갖는 셀(cell)을 같은 색으로 설정하는 VBA (0) | 2016.01.07 |