Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ iterator over certain elements in vector

Tags:

c++

iterator

stl

Please forgive me if this is a trivial question, I'm just learning C++ and try to wrap my head around certain concepts. Especially when it comes to iterators, I'm completely lost.

Say I have a custom class representing some data structure, and one of its members is a vector of integers. I want to write a bidirectional iterator for that class, which outputs only the EVEN numbers in the vector. Is there an easy and instructive way? I'd prefer not using libraries other than STL.

like image 707
user32849 Avatar asked Sep 10 '14 18:09

user32849


2 Answers

Not sure making your own iterator is easy. But probably the best is to use a conditional for_each functions.

std::for_each does an operation on every elements. It's pretty easy to create a for_each_if doing an operation on some specific elements. For instance, program below only prints even numbers from the vector (4, 6 and 8).

#include <iostream>
#include <vector>

using namespace std;

struct is_even {
  typedef bool return_type;
  bool operator() (const int& value) {return (value%2)==0; }
};

struct doprint {
  bool operator() (const int& value) { std::cout << value << std::endl; }
};

template <class InputIterator, class Predicate, class Function> 
void for_each_if(InputIterator first, InputIterator last, Function f, Predicate pred) 
{ 
    while ( first != last )
    {  
        if (pred (*first)) 
            f(*first++);  
        else 
            first ++; 
    }
}

int main()
{
   std::vector<int> v;
   v.push_back( 4 );
   v.push_back( 5 );
   v.push_back( 6 );
   v.push_back( 8 );

   for_each_if( v.begin(), v.end(), doprint(), is_even());

   return 0;
}
like image 114
jpo38 Avatar answered Sep 30 '22 01:09

jpo38


Going by your requirements, deriving from vector::iterator would probably be the easiest:

class my_iterator : private std::vector<int>::iterator {
    typedef std::vector<int>::iterator base;
    base m_base_end;   // Stores the real end iterator of the internal vector.
                       // We need it so that the even/odd checking code
                       // doesn't run off the end of the vector
                       // (initialize it in a constructor, omitted here for
                       // brevity).
public:

    using base::operator*;
    using base::operator->;
    // etc. for other members...

    // except for increment:

    my_iterator& operator++()
    {
        do {
            base::operator++();
        } while( static_cast<base&>(*this) != m_base_end
                 && base::operator*() % 2 );
        return *this;
    }

    my_iterator operator++(int)
    {
        my_iterator temp;
        operator++();
        return temp;
    }

    // TODO: decrement and other arithmetic operators
};

It's still quite a bit of boilerplate, and you'll also want to do the same for const_iterator (I'd probably make the above class a template to make it easier).

Consider Boost for this - it has filter_iterator just for this purpose. There's also iterator_adaptor if that doesn't suit you.

like image 43
jrok Avatar answered Sep 30 '22 00:09

jrok