WestFlame
WestFlame

Reputation: 435

comparing two different boost::iterator_facade iterators

I have two iterators, both derive from boost::iterator_facade (but not from each other) and I want to be able to compare them because I don't want to have more end() methods when one is sufficient. Is it possible?

The following minimal example is not working for me, but I think it should. What am I doing wrong?

#include <vector>
#include <iostream>

#include <boost/iterator/iterator_facade.hpp>

using namespace std;

typedef vector<int>         val_type;
typedef vector<val_type>    vec_type;

class myiterator
  : public boost::iterator_facade<
        myiterator
      , val_type
      , boost::forward_traversal_tag
    >
{
private:
    friend class boost::iterator_core_access;
    friend class base_myiterator;

public:
    explicit myiterator(vec_type::iterator _it)
        : it(_it)
    {}

    myiterator(myiterator const& other)
        : it(other.it)
    {}

 private:
    void increment() { ++it; }

    bool equal(myiterator const& other) const
    {
        return (it == other.it);
    }

    val_type& dereference() const { return *it; }

    vec_type::iterator it;
};

class base_myiterator
  : public boost::iterator_facade<
        base_myiterator
      , val_type
      , boost::forward_traversal_tag
    >
{
private:
    friend class boost::iterator_core_access;

public:
    explicit base_myiterator(vec_type::const_iterator _it, val_type _base)
      : base(_base),
        it(_it)
    {
        idx.resize(base.size());
    }

    base_myiterator(base_myiterator const& other)
      : base(other.base),
        it(other.it)
    {
        idx.resize(base.size());
    }

 private:

    void increment()
    {
        ++it;
        for (size_t i=0; i<base.size(); ++i)
        {
            idx[i] = base[i] + (*it)[i];
        }
    }

    bool equal(base_myiterator const& other) const
    {
        return (it == other.it);
    }

    bool equal(myiterator const& other) const
    {
        return (it == other.it);
    }

    val_type const& dereference() const
    {
        return idx;
    }

    val_type base;
    vec_type::const_iterator it;
    val_type idx;
};

struct Sample
{
    vec_type vec;

    myiterator begin()
    {
        return myiterator(vec.begin());
    }

    base_myiterator begin(val_type const& base)
    {
        return base_myiterator(vec.begin(), base);
    }

    myiterator end()
    {
        return myiterator(vec.end());
    }
};

int main ()
{
    Sample s;

    val_type val;
    val.push_back(1); val.push_back(0);
    s.vec.push_back(val);
    val.clear(); val.push_back(0); val.push_back(1);
    s.vec.push_back(val);

    val.clear(); val.push_back(-5); val.push_back(5);

    //for (myiterator it=s.begin(); it!=s.end(); ++it)
    for (base_myiterator it=s.begin(val); it!=s.end(); ++it)
    {
        cout << (*it)[0] << " " << (*it)[1] << endl;
    }
}

Upvotes: 2

Views: 795

Answers (1)

Andreas Hehn
Andreas Hehn

Reputation: 138

boost::iterator_facade checks if two iterators are interoperable before instantiating the relation operators.

It uses boost::type_traits::is_convertible to check if it is legal to convert one type of iterator into the other type. Thus if you add a constructor base_myiterator(myiterator const& other) it will work. It will use the special equal overload you provided and not do any conversion (i.e. the additional copy constructor won't be used, it just needs to be there).

Furthermore, the base_myiterator seems to operate as some sort of const_iterator (val_type const& reference() const). In this case you should pass val_type const as template parameter Value to iterator_facade as described here.

Upvotes: 2

Related Questions