Custom input iterator

I have a read-only user-defined data structure that I need to translate. I would like to create a custom iterator that should skip specific values.

A simple but equivalent example might be the following. I have a vector of numbers and I want to skip all the missing negative values. Usually I would do something like:

vector<int> v; for (vector<int>::iterator it = v.begin(); it!=v.end(); ++it) { if (*it > 0) { dosomething(*it); } } 

But I would like to do something like:

 vector<int> v; for (vector<int>::my_iterator it = v.my_begin(); it!=v.my_end(); ++it) { dosomething(*it); } 

What is the right way to achieve this?

+4
source share
3 answers

This is easily achieved with boost::filter_iterator if your data structure already stores the container under the hood. Here is a simple example:

 #include <vector> #include <iostream> #include <boost/iterator/filter_iterator.hpp> class X{ typedef std::vector<int> container; struct Pred{ bool operator()(int i){ return i % 2 == 0; } }; public: typedef boost::filter_iterator<Pred, container::iterator> iterator; void add(int val){ nums.push_back(val); } iterator begin(){ return iterator(nums.begin(), nums.end()); } iterator end(){ return iterator(nums.end(), nums.end()); } private: container nums; }; int main(){ X x; for(int i=0; i < 10; ++i) x.add(i); for(X::iterator it = x.begin(), ite = x.end(); it != ite; ++it) std::cout << *it << ' '; } 

Live example in Ideone. Exit:

0 2 4 6 8

+2
source

This is not a very pleasant solution, but I will send it anyway. Any attempt to dereference this iterator shell will force it to check the current value and advance the iterator for any negative values. It will be called recur

 template<typename InputIterator> struct nonnegative_iterator : InputIterator { template<typename Arg> nonnegative_iterator(Arg i) : InputIterator(i) { } typename InputIterator :: reference operator* () { typename InputIterator :: reference x = InputIterator :: operator*(); if( x < 0) { ++ (*this); // equivalent to this -> operator++ () return **this; } else return x; } }; 

which can be used as follows:

  for ( nonnegative_iterator< vector<int>::iterator > it = v.begin(); it!=v.end(); ++it) { 

This has some problems, for example, I did not implement the const method to allow the value_type to be value_type . Therefore, use at your own peril and risk!

+2
source

Assuming you are not in control of the vector<int> interface, for example. because it’s actually std::vector<int> , the first thing you want to do is change the way you get custom iterators. That is, instead of writing

 for (vector<int>::my_iterator it = v.my_begin(); it != v.my_ned(); ++it) 

would you use

 for (my_iterator it(my_begin(v)), end(my_end(v)); it != end; ++it) 

You can create a modified interface for the custom container, but it's a big fish to fry. Creating an input iterator now essentially boils down to creating a suitable wrapper for the main iterator. It might look something like this:

 template <typename InIt, Pred> struct my_iterator { typedef typename std::iterator_traits<InIt>::value_type value_type; typedef typename std::iterator_traits<InIt>::difference_type difference_type; typedef typename std::iterator_traits<InIt>::reference reference; typedef typename std::iterator_traits<InIt>::pointer pointer; my_iterator(InIt it, InIt end, Pred pred): it_(it), end_(end), pred_(pred) {} bool operator== (my_iterator const& other) const { reutrn this->it_ == other.it_; } bool operator!= (my_iterator const& other) const { return !(*this == other); } reference operator*() { return *this->it_; } pointer operator->() { return this->it_; } my_iterator& operator++() { this->it_ = std::find_if(this->it_, this->end_, this->pred_); return *this; } my_iterator operator++(int) { my_iterator rc(*this); this->operator++(); return rc; } private: InIt it_, end_; Pred pred_; 

The functions my_begin() and my_end() will then create a suitable object of this type. One approach to avoid having to write this is to take a look at the Boost iterator adapters: there should be something suitable.

+2
source

Source: https://habr.com/ru/post/1393547/


All Articles