The Lazy Programmer

June 4, 2008

C++: Using Boost ranges to simplify enumerations

Filed under: C#,Programming — ferruccio @ 8:58 pm
Tags: , , ,

Let’s say you’ve created a class which encapsulates an STL-style container and you now need to expose the data in that container. There are a few possibilities which we’ve probably all tried and found to be unsatifactory.

  • You could simply expose the container, either as a public member or with a method that returns either a pointer or reference to it. The problem is, once you throw away the encapsulation, your code becomes tightly coupled and that’s not a good thing.
  • You could provide GetFirst()/GetNext() type of functions. These type of functions make it a little easier for your class to be used, but now you have to maintain an internal iteration state which will not work out very well if your data is being examined by more than one thread.
  • Another approach is to provide an enumeration function with some sort of callback mechanism. A virtual function defined as part of the interface, or you could pass in a function pointer or functor. Now you’re setting up a lot of boilerplate code without much gain. And to make things worse, you really haven’t decreased coupling all that much
  • You could return an iterator. You would actually have to return two: a beginning and an end. This is actually pretty close to the approach I’ve settled on. I’m going to use a combination of the boost range library and the BOOST_FOREACH macro.

What is a range?

A range is simply a pair of iterators. One iterator points to the beginning of your container, the other points just past the end of that same container. The begin() and end() methods of a container form a range. Ranges are used all over the place inside the STL and Boost. The Boost range library gives you a way to create and use ranges directly in your code.

The best way to demonstrate this idea is with some code, so here we go:

#include <string>
#include <list>
#include <iostream>
using namespace std;

#include <boost/foreach.hpp>
#include <boost/range.hpp>
using namespace boost;

class Test
{
public :
   Test() : data_()
   {
      data_.push_back("eenie");
      data_.push_back("meenie");
      data_.push_back("miney");
      data_.push_back("moe");
   }

   typedef iterator_range<list<string>::const_iterator> range_iter;

   range_iter Enumerate()
   {
      return make_iterator_range(data_);
   }

private :
   list<string> data_;
};

int main(int argc, char** argv)
{
   Test t;

   BOOST_FOREACH (Test::range_iter::reference s, t.Enumerate())
   {
      cout << s << endl;
   }

   return 0;
}

The range_iter typedef defines our range type. In this case a const_iterator range to a list of strings. The const_iterator makes it possible to efficiently expose our data in a readonly manner.

The Enumerate() function simply returns a range created by the make_iterator_range() function. If you want to return only a portion of the container, you can create a range from a pair of iterators. The important thing is that although the range is attached to your container, the caller has no idea what kind of container it is dealing with. All it has to do is process the objects referenced by the range as shown in the BOOST_FOREACH loop.

The BOOST_FOREACH macro really ties it all together nicely. It makes it possible to process the items in an STL container (or range) without all the usual iterator syntax (begin(), end(), etc.)

References

Boost Range Library

BOOST_FOREACH

Advertisements

Create a free website or blog at WordPress.com.

%d bloggers like this: