Reputation: 25612
I'm trying to make a simple preprocessor loop. (I realize this is a horrible idea, but oh well.)
// Preprocessor.h
#ifndef PREPROCESSOR_LOOP_ITERATION
#define MAX_LOOP_ITERATION 16 // This can be changed.
#define PREPROCESSOR_LOOP_ITERATION 0
#endif
#if (PREPROCESSOR_LOOP_ITERATION < MAX_LOOP_ITERATION)
#define PREPROCESSOR_LOOP_ITERATION (PREPROCESSOR_LOOP_ITERATION + 1) // Increment PREPROCESSOR_LOOP_ITERATION.
#include "Preprocessor.h"
#endif
The issue is that it doesn't look like PREPROCESSOR_LOOP_ITERATION
is being incremented, so it just keeps including itself infinitely. If I change the line to an actual integer (like 17
), the preprocessor skips over the #include
directive properly.
What am I doing incorrectly?
Upvotes: 3
Views: 20064
Reputation: 7470
EDIT: As James pointed out, my original solution did not work due to lazy evaluation of macros. If your compiler supports it, the macro __COUNTER__
increments by one every time it is called, and you can use it to do a simple preprocessor loop like this:
// Preprocessor.h
#define MAX_LOOP_ITERATION 16 // Be careful of off-by-one
// do stuff
#if (__COUNTER__ < MAX_LOOP_ITERATION)
#include "Preprocessor.h"
#endif
I verified this in Visual C by running cl /P Preprocessor.h
.
Upvotes: 6
Reputation: 355307
The "problem" is that macros are lazily evaluated. Consider your macro definition:
#define PREPROCESSOR_LOOP_ITERATION (PREPROCESSOR_LOOP_ITERATION + 1)
This defines a macro named PREPROCESSOR_LOOP_ITERATION
and its replacement list is the sequence of five preprocessing tokens (
, PREPROCESSOR_LOOP_ITERATION
, +
, 1
, and )
. The macro is not expanded in the replacement list when the macro is defined. Macro replacement only takes place when you invoke the macro. Consider a simpler example:
#define A X
#define B A
B // this expands to the token X
#undef A
#define A Y
B // this expands to the token Y
There is an additional rule that if the name of a macro being replaced is encountered in a replacement list, it is not treated as a macro and thus is not replaced (this effectively prohibits recursion during macro replacement). So, in your case, any time you invoke the PREPROCESSOR_LOOP_ITERATION
macro, it gets replaced with
( PREPROCESSOR_LOOP_ITERATION + 1 )
then macro replacement stops and preprocessing continues with the next token.
You can perform limited arithmetic with the preprocessor by defining a sequence of macros and making use of the concatenation (##
) operator, but it's quite tedious. You should consider using the Boost.Preprocessor library to help you with this. It will work with both C and C++ code. It allows for limited iteration, but what it does allow is extraordinarily useful. The closest feature that matches your use case is likely BOOST_PP_ITERATE
. Other facilities like the sequence (BOOST_PP_SEQ
) handlers are very helpful for writing generative code.
Upvotes: 9
Reputation: 882606
Seriously, find another way to do this.
The preprocessor should be relegated to include guards and simple conditional compilations.
Everything else it was ever useful for has a better way to do it in C++ (inlining, templates and so forth).
The fact that you state I realize this is a horrible idea ...
should be a dead giveaway that you should rethink what you're doing :-)
What I would suggest is that you step back and tell us the real problem that you're trying to solve. I suspect that implementing recursive macros isn't the problem, it's a means to solve a problem you're having. Knowing the root problem will open up all sorts of other wondrous possibilities.
Upvotes: -2