Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Writing an iterator that makes several containers look as one

Tags:

Consider the following simplified example and desired output:

class A {     class combined_iterator     {         ????     }     typedef ??? t_combined_it;      t_combined_it begin();     t_combined_it end();      std::vector<int> m_Vec1, m_Vect2; }  A a; a.m_Vec1.push_back(1); a.m_Vec2.push_back(2); for (A::t_combined_it it = a.begin() ; it != a.end() ; it++) {      std::cout << *it << " "; } 

Output:

1 2  

I think the question is clear from this: how do I write an iterator that makes it look as if two or more other iterators are really just one sequence. So that, in the example, instead of iteration over both m_Vec1 and m_Vec2, I can use an iterator that iterates over first the elements of m_Vec1 and then m_Vec2, transparently.

I found the following question which I think asks the same: Make a c++ iterator that traverses 2 containers . There were no good answers to this question; the solution presented by the original asker seems convoluted, and it is (relatively) memory-intensive.

I tried a naive approach by keeping a std::vector::iterator as a member of my custom iterator, and comparing it to the .end() iterators of each of the sequences being iterated over; however it seems that it is illegal to compare iterators from different containers (where I would have preferred them just to return 'not equal' - maybe that is a direction to go for finding the solution to this problem? I can't think of how to implement it, though).

Where possible and if relevant, I would like to use boost::iterators as I use them elsewhere and I like the homogeneity it provides to my iterator implementations; but of course if someone has an idea without using them, I can work them in myself, so they're not required in that sense.

like image 256
Roel Avatar asked Jul 19 '11 13:07

Roel


People also ask

What is a bidirectional iterator?

Description. A Bidirectional Iterator is an iterator that can be both incremented and decremented. The requirement that a Bidirectional Iterator can be decremented is the only thing that distinguishes Bidirectional Iterators from Forward Iterators.

What is the strongest iterator that list provides?

Random-Access Iterators: They are the most powerful iterators. They are not limited to moving sequentially, as their name suggests, they can randomly access any element inside the container.

What is the use of iterator while using containers?

An iterator is an object (like a pointer) that points to an element inside the container. We can use iterators to move through the contents of the container. They can be visualised as something similar to a pointer pointing to some location and we can access content at that particular location using them.


2 Answers

I think your "naive" approach should work, with the following change: instead of comparing the iterator to the end() of every container, keep a pointer to the current container and compare the iterator only the the current container's end(). When the end has been reached, move on to the next container. That way, you'll never compare the iterator to another container than the one it points to. This will also easily generalize to an arbitrarily-sized collection of collections.

like image 32
Aasmund Eldhuset Avatar answered Nov 01 '22 13:11

Aasmund Eldhuset


boost::join is what you're looking for. You can also study the implementation, especially how to derive the lowest common denominator for container traversal, reference and return value types. To quote:

The intention of the join function is to join two ranges into one longer range.

The resultant range will have the lowest common traversal of the two ranges supplied as parameters.

Note that the joined range incurs a performance cost due to the need to check if the end of a range > has been reached internally during traversal.

like image 72
Sebastian Avatar answered Nov 01 '22 13:11

Sebastian