Maxpm
Maxpm

Reputation: 25612

Incrementing Preprocessor Macros

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

Answers (3)

irritate
irritate

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

James McNellis
James McNellis

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

paxdiablo
paxdiablo

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

Related Questions