Is there a way to expand the macros when the macro is defined.
Yes. But beware... using this as a means of generating unique symbols may cause unexpected linker issues if your symbols have external linkage.
Overview
The key problem here is that macros are not variables. With variables, if I have x=3*3; y=x;
, then I'm assigning the value of x to y. With macros, if I have #define PPX 3*3
#define PPY PPX
, then I'm literally assigning PPX
to PPY
. If I then evaluate PPY
, it expands to PPX
, and then to 3*3
but only because PPX
is currently defined as 3*3
.
However, there is a way around this. The preprocessor can evaluate expressions; it just uses conditional directives to do so. But due to the fact that this can branch, we can define macros conditionally based on PPX's
value (as opposed to its replacement list). For example:
#if (PPX)%10==9
# define PPX_DIGIT_0 9
#elif (PPX)%10==8
# define PPX_DIGIT_0 8
...
So whereas PPY
critically relies on PPX
being defined as 3*3
to expand to 3*3
; since PPX_DIGIT_0
is literally defined as 9
, PPX
can be undefined, and PPX_DIGIT_0
will still expand to 9. Note also that the conditional played a role in reducing the expression; (3*3)%10
is just equal to 9, causing the 9 branch to be hit. That loses the expression per se, picking up just the evaluation... which we want.
That's the idea. In practice, this requires a fair amount of code; fortunately, boost's preprocessor library already has it done for you, so here are two approaches using boost:
Approach 1: Using Boost Slots
include_counter.h
:
#include <boost/preprocessor/slot/slot.hpp>
#if !(INCLUDE_COUNT)
# define INCLUDE_COUNT 0
# define BOOST_PP_VALUE INCLUDE_COUNT
# include BOOST_PP_ASSIGN_SLOT(1)
# undef BOOST_PP_VALUE
# undef INCLUDE_COUNT
# define INCLUDE_COUNT BOOST_PP_SLOT(1)
#endif
#define BOOST_PP_VALUE 1+INCLUDE_COUNT
#include BOOST_PP_ASSIGN_SLOT(1)
Boost slots evaluate macros and store their results using special internal states. You get 5 slots (code above is using slot 1), so you can store 5 numbers. This solution just initializes the slot to 0 before incrementing on the first include, then essentially just increments.
Approach 2: Use Boost Counter
include_counter.h
:
#if !(INCLUDE_COUNT)
# include <boost/preprocessor/slot/counter.hpp>
# define INCLUDE_COUNT BOOST_PP_COUNTER
#endif
#include BOOST_PP_UPDATE_COUNTER()
Same idea, though it "consumes" boost counter.
Both boost solutions take the approach I just described. There's also a boost increment macro; feel free to ignore that, since (a) you're evaluating anyway, and (b) boost increment is a bit whimpy (with its maximum limit of 256).
You can also roll your own solution. But when you're done, it's going to look similar to boost's solution anyway. (The advantage is, your new "slot" will be independent of boost counter and boost slots).
INCLUDE_COUNT
is helping to set a specific name of a struct in a file, which is included multiple times, it should emulate a c++-template in c, only that it is built by including a file and defining the template-parameters by macros before the include and undefined after. – cmdLP__COUNTER__
macro. It's supported by gcc and Microsoft compilers. – kaylum__COUNTER__
increases outside the header, when otherwise used. But thanks for the tip. – cmdLP