What is wrong with STL iterators? To see the shortcomings, let's dream up a better one and then compare.
Our hypothetical interface to iterators will have the following methods:
bool not_done(); // Is the iterator done?
void next(); // Move to the next value. Throws exception if done.
Foo value(); // What value do we have? Throws exception if done.
Our data structures will support the method iterator() that is the moral equivalent of begin().
We already have the equivalent of STL iterators. You just change:
for (data_structure::iterator it = foo.begin(); it != foo.end(); ++it) { /* do stuff with it / }
to
for (iterator< fooish > it = foo.iterator(); it.not_done(); it.next()) { /* do stuff with it.value() */ }
So far uninteresting. But with this new interface we can add four interesting templates in a straightforward matter.
1. Take an iterator< fooish > and a function that maps things of type fooish to type barish, then produce an iterator< barish >.
2. Take an iterator< fooish >, and a function that maps fooish to bool, then produces an iterator that gives you just the ones that mapped to true.
3. (Generalization of the first two.) Take an iterator that produces things of type fooish, and a function that maps fooish to iterator< barish >, and returns an iterator< barish > that just maps each value from the first to all of the bars that it produces.
4. Take an object with a method that produces things of type fooish, and produce an iterator< fooish >.
These are all simple to define given this interface. What do they allow us to do? Well the article that introduced me to the idea of iterators was http://perl.plover.com/Stream/stream.html - absolutely everything in that article is straightforward with the interface that I described and absolutely none of it is easy with STL iterators. (It is all still actually possible, but tricky. Proving that fact is left as an exercise to the reader, at which point you'll know why people don't tend to think about problems that way in C++.)