Lately I have been needing to implement small classes that generate a bunch of numbers. It would be very convenient if C++ had generators like python, but unfortunately it is not so.
So I have been thinking of how to best implement these types of objects, for easy iteration and composition. When we think of iterators over containers, they essentially only hold the index to an element, and the bulk of the information is in the container itself. This allows for several iterators to be referencing different elements within a collection at the same time.
When it come to state machines, it becomes apparent that the iterator will have to hold the whole state as several iterators need to be able to be independent. In that sense, the state machine class is more of a “builder” of these iterators which are the actual state machines.
As a toy example I have implemented the range generator (ala xrange in python), that can be used in loops:
// using range-for from c++11
for (auto i : range<int>(1, 30)) {
cout << i << endl;
}
The code can be found on my bitbucket.
That said, it is awkward to store the whole state within the iterator, since the end() iterator is created just for the sake of comparing the ending state, which wastes space if the state is a large collection of members.
Has there been anything done with simple linear state machines, and looping over them with iterators?
If you support only forward iteration, you might be able to get away with using a different type for end() then for begin(). Here’s the basic idea
I’ve never tries this though, so I can’t guarantee that this will work. Your state-machine’s
iteratorandconst_iteratortypedefs will specify a different type thanend()returns, which may or may not cause trouble.Another possibility is to go with a variation on pimpl which uses
boost::optional. Put the iterator state into a separate class, and store it within aboost::optionalwithin the iterator. Leave the state unset for the iterator returned byend(). You won’t save any memory, but you avoid heap allocations (boost::optional doesn’t do any, it uses placement new!) and initialization overhead.