The problem appears to be that when we just call visit, we are out of control, and can't temporarily "go back" to the loop body to execute the action for one node. This looks like it should occur regularly in real world programs. Any idea how to solve it?

3 Answers
3

In the general case, I don't think it's possible, at least not cleanly.

At least as it's usually defined, an iterator expects to deal with a homogeneous collection. I.e., an iterator is normally defined something like:

template <class Element>
class iterator // ...

...so a specific iterator can only work with elements of one specific type. The most you can do to work with differing types is create an iterator to (a pointer/reference to) a base class, and let it deal with objects of derived classes.

This can visit nodes of either OneType or AnotherType, even if the two are completely unrelated. Basically, you have one Visit member function in your Visitor class for every different type of class that it will be able to visit.

Looked at from a slightly different direction, an iterator is basically a specialized form of visitor that only works for one type of object. You exchange a little more control over the visitation pattern in exchange for losing the ability to visit unrelated types of objects.

If you only need to deal with one type (though that one type may be a base class, and the visited objects are of various derived types), then the obvious method would be to build a "bridge" class that visits objects (Tree nodes, in your example), and when its visit is called, it just copies the address of the node it's visiting into some collection that supports iterators:

Using this would be a two-step process: first visit the nodes like a visitor normally would, then having collected together the nodes of interest you can iterate through them just like you would any other collection that provides iterators. At that point, your visitation pattern is limited only by the class of iterator provided by the collection you use in your bridge.

Building traversal logic in the visitors implementations is indeed not flexible. A usable way to cleanly separate traversing composite structures from visitation may be done via visitor combinators (there are other papers, feel free to google for them).

These slides about the same topic may also be of interest. They explain how to get clean syntax à laboost::spirit rules.

I had this problem in a real-world setting with an R-tree implementation that provided a visitor interface, whereas I needed an iterator interface. The suggestion by Jerry above works only if you can accept storing all the results in a collection. That may result in high memory consumption if your result set is huge and you don't really need to store them.

One solution that will work for sure is to launch the visitor in a separate thread and start waiting on a conditional variable for the results. When a visit call is made, you store the current result into a shared temp location, and use another conditional variable to wait for the next request. You signal the caller (main) thread's conditional variable before you wait on your own. The caller, which is implementing the iterator interface can then return the value stored at the temp location. During the next iteration, it could signal the visitor thread's conditional variable, and wait on its own for the next item. Unfortunately, this is somewhat costly if you do it on a per-item basis. You can buffer some items to improve the performance.

What we really need is an extra stack and to alternate between two contexts. This abstraction is provided by coroutines. In C++, boost::coroutine provides a clean implementation. Below I include a full example of how visitor pattern can be adapted into an iterator pattern.