Setepenre
Setepenre

Reputation: 2043

Creating my own Iterators for non stl container

I have a class that manage data.

I wish to return only a part of the data that is inside it, but since it is a process that will be done multiple times I do not wish to just copy the data inside a container and return the container.

It would be nice if I could just send a reference or something similar. Iterators come to mind. but since I use Eigen3 Matrix (which does not have iterators (2D matrix anyway))

I am thinking of emulating(?) the iterators behavior, something like that:

typedef unsigned int Index;

class MatrixIterator
{
public:
    MatrixIterator(Eigen::MatrixXd *m, Index min, Index max):
        _col(0), _index(0), _min(min), _max(max), _matrix(m)
    {}

    void operator++ ()   
    {
        if (_index + _min + 1 != _max)
            _index++; 
    }
    void operator--()
    {
        if (_index != _min)
            _index--; 
    }

    double operator*()
    { 
        return _matrix->operator() (_index + _min, _col); 
    }

    void setCol(Index col)  {   _col = col; }

    Index min() {   return _min;    }
    Index max() {   return _max;    }

private:
    // the matrix is 2D we can select
    // on which column we want to iterate
    Index _col;

    // current position
    Index _index;

    // select the range on which the user can iterate
    Index _max;
    Index _min;

    // the matrix on which we want to iterate over
    Eigen::MatrixXd* _matrix;
}

I have read :

EDIT : I want to iterate over only a part of the matrix (that is why I have _min and _max), the data I am manipulating are time series so the data are already ordered. I think we can consider MatrixIterator as a response to a data query.

Upvotes: 2

Views: 969

Answers (1)

Mikael Persson
Mikael Persson

Reputation: 18562

I never really used iterators before, is it correct ?

It's a good start. The idea is correct, but you are missing a few things. First, you don't have enough operators. Make sure you check the reference and provide every operator that you can sensibly provide (the only ones that may or may not be useful are random-access operators, because it could be harder to implement for this case). Second, you need to provide the iterator traits for your iterator class. This is usually done by creating the necessary nested typedefs in your iterator class (you could also specialize the std::iterator_traits template for your class, but I would say that this is only when you really cannot add the nested typedefs).

Can I inherit my MatrixIterator from std::iterator so stl would be able to understand it as a usual iterator ?

No, you should not, in general, inherit from the std::iterator class. The STL is a template library (generic programming (GP)) and therefore, does not use the base-class inheritance model as in OOP. The STL algorithms take iterators as template arguments, and will generically use them as required by the algorithm (or as possible by the iterator_category trait associated to the iterator type). This is generic programming, not object-oriented programming, it's apples and oranges.

Do you know a better way to do something similar ?

Well, one convenient way to do this is by using a class template like boost::iterator_facade (see ref) which provides a sort of automated "fill in the blanks" mechanism creating iterators. It uses the well-known and very useful Curiously Recurring Template Pattern (or CRTP for short). This is useful because implementing all the operators required for iterators can be quite verbose and repetitive, and the usually only really rely on just a few core operations (which is all you need to "fill in" when using a CRTP class like boost::iterator_facade).

Upvotes: 2

Related Questions