12 Sep 2003 elanthis   » (Journeyer)

C++ Foreach Loop

I got my C++ foreach loop working almost 100%. Go me!

code is here

It makes use of one GCC extension (altho it's popular in other compilers), namely the typeof() construct. Unfortunately, there are some "bugs" (or just poor design) that creates a couple buglets in my code.

First off, the foreach() construct can't be used as a single statement. I define a macro foreach, and that is forced into two statements: a typedef and a for loop. I have to have the typedef because I can't do anythign like typeof(expression)::identifier, but instead have to do typedef typeof(expression) my_type; my_type::identifier.

Furthermore, typeof() seems to have mixed results when the expression given is a class constructor invocation. In some cases, it gives back the class (the "return" type of the constructor), while other times it gives back the constructor's function signature (which isn't what I want). That can, at least, be worked around by using a function or static method that just returns a constructed object for you. It's still a bit of a pain, tho.

In any event, the code does work amazingly well. I even have an STL wrapper, so you use code like:

vector<int> int_vector; ... foreach(i, STLIterator(int_vector)) cout << *i << endl;

You may notice the *i - it's a small necessity. The i variable isn't actually an int, as one might expect, but an iterator wrapper that I had to use to keep the foreach() loop down to one for loop (and the typedef I hope to find a way to get rid of). So you need to call *i (or i->) to get to the value.

The code also properly supports iterators that use references, so it doesn't have to copy values around. (i.e., it's safe to iterate over a list of large or copy-expensive types.)

The interface for custom iterators is very simple. Basically, you just derive from an Iterator<T> template, where T is the type you return on each iteration. You then define an Iterate method, which takes a "magic" out parameter, and returns a bool. You return true and set the out parameter and each call, or just return false if the iteration is over (end of list).

The base Iterator class makes the Iterate() method a virtual method. I did this only because i wanted an abstract virtual method so the compiler will complain with a nice error message if you don't define it in your subclass. It doesn't need to be virtual otherwise, tho, and it would cut down on object size for most iterators if it wasn't virtual (the template code will handle the inheritane fine), which is a good thing even if GCC should optimize out the virtual call to a static call at compile time.

Iterators do go thru one copy on call to foreach(), which is necessary in the case of temporary objects, altho I could probably find some template magic to get rid of the copy in cases where it's not needed. Ah well. ;-)

All in all, it's quite cool. If I can get some portability tests (or reports from others), I might even package it up a little nicer and release it under a BSD license or some-such, as it certainly can make C++ coding a lot more pleasant. (Even if just used to wrap STL iterators - those loops get *ugly*.)

AweMUD

I'm hoping to get AweMUD 0.19 and related libraries released this weekend. Reports show it is pretty stable on Linux, and I've also received confirmation that Cygwin support is working, so that (along with the many cool, awesome new features) will make for a great release.

I'd love to double check that Mac OS X works, as well, so I can add it to the "officially supported" platforms list for the release.

Latest blog entries     Older blog entries

New Advogato Features

New HTML Parser: The long-awaited libxml2 based HTML parser code is live. It needs further work but already handles most markup better than the original parser.

Keep up with the latest Advogato features by reading the Advogato status blog.

If you're a C programmer with some spare time, take a look at the mod_virgule project page and help us with one of the tasks on the ToDo list!