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?
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With