I should also note that the disadvantages of this sort of meta-language macroing are many. It makes code harder to share. It makes code harder for people who aren't in your system to read. It makes debugging harder if there's ever a problem in the macro. It can create bugs due to the macro not doing exactly what's expected. etc.
It's just stylistic. In the previous discussion someone suggested it. I do think there is merit in leaving the flow control indicators outside of the macros.
We talked a while ago about how annoying and error-prone for loops are in C. Well at first I was hesitant,
but lately I have started using "for LOOP" in earnest and I can now say that I like it very much.
#define LOOP(var,count) (int var=0;(var) < (count);var++)
#define LOOPBACK(var,count) (int var=(count)-1;(var)>=0;var--)
#define LOOPVEC(var,vec) (int var=0, loopvec_size = (int)vec.size();(var) < (loopvec_size);var++)
so for example, to iterate pixels on an image I now do :
for LOOP(y,height)
{
for LOOP(x,width)
{
// do stuff
}
}
the way I can tell that this is good is because I find myself being annoyed that I don't have it in my RAD
code.
There are tons of advantages to this that I didn't anticipate. The obvious advantages were : less bugs due to
mistakes in backwards iteration with unsigned types, reducing typing (hence less typo bugs), making it visually
more clear what's happening (you don't have to parse the for(;;) line to make sure it really is a simple counting
iteration with nothing funny snuck in.
The surprising advantages were : much easier to change LOOP to LOOPBACK and vice versa, much easier
to use a descriptive variable name for the iterator so I'm no longer tempted to make everything for(i).
One thing I'm not sure about is whether I like LOOPVEC pre-loading the vector size. That could cause unexpected
behavior is the vector size changes in the iteration.
ADDENDUM :
Drew rightly points out that LOOPVEC should be :
#define LOOPVEC(var,vec) (int var=0, var##size = (int)vec.size();(var) < (var##size);var++)
to avoid variable name collisions when you nest them. But I think it should probably just be
#define LOOPVEC(var,vec) (int var=0; (var) < (int)vec.size(); var++)
Though that generates much slower code, when you really care about the speed of your iteration you can pull
the size of the vec out yourself and may do other types of iterations anyway.
"02-23-11 - Some little coder things - Loop"
8 Comments -
Mine is
#define FOR_EACH( it, coll ) for (coll##_TYPE::iterator it = coll.begin(); it != coll.end(); ++it)
and then I can just type e.g.
FOR_EACH( it, mNotes ) { (*it)->Play(); }
I then do have to #define a foo_TYPE for each collection foo, but since I am generally only doing this for member variables, it's not so bad.
This is the only way I can bear to deal with STL iterators rather than indices.
February 24, 2011 at 7:13 AM
"#define FOR_EACH( it, coll ) for (coll##_TYPE::iterator it = coll.begin(); it != coll.end(); ++it)"
Hmm.. the need for _TYPE types without typeof or auto types.
It will be much nicer in C++0x
February 24, 2011 at 10:18 AM
I should also note that the disadvantages of this sort of meta-language macroing are many. It makes code harder to share. It makes code harder for people who aren't in your system to read. It makes debugging harder if there's ever a problem in the macro. It can create bugs due to the macro not doing exactly what's expected. etc.
February 24, 2011 at 11:17 AM
Interesting that you put the "for" outside the macro. Does this help something non-obvious, or is it just a stylistic thing?
February 24, 2011 at 4:17 PM
It's just stylistic. In the previous discussion someone suggested it. I do think there is merit in leaving the flow control indicators outside of the macros.
February 24, 2011 at 11:44 PM
For some more inspiration, or perhaps brain-meltage, check out Common Lisp's LOOP macro / mini-language:
http://www.gigamonkeys.com/book/loop-for-black-belts.html
February 27, 2011 at 8:56 PM
#undef
March 9, 2011 at 5:30 AM
LOL, well played.
March 9, 2011 at 8:52 AM