RE: [boost] preprocessor fix

Not a bug. Empty macro arguments are currently undefined behavior in C++. There is nothing that I can do about that. C99 added explicit support for them, but they are not (yet) part of C++.
I very much appreciate your answer. And ultimately this hasn't become a big deal, since - as you saw - I found a way around the problem all the same. But now let me answer a very good question you asked:
#define ENUM(name, start, entries)\ BOOST_PP_SEQ_ENUM( \ BOOST_PP_IIF(ENUMS, \ (typedef enum{ BOOST_PP_SEQ_HEAD(entries) = start) \ BOOST_PP_SEQ_TAIL(entries) \ (LAST_##name } name;) \ , \ (static void PP_NILFUNC();) \ ) \ )
Why are you doing the test *inside* of the invocation of SEQ_ENUM?
The short answer: I wanted a **single** ENUM macro definition that permitted the printable strings *AND* the enums themselves to be conditionally compileable. I think my intention will make more sense if I show you the entire printable enum. It looks like this: #ifndef ENUMS /*By default, turn enums on*/ #define ENUMS 1 #endif #ifndef ESTRINGS /*By default, turn printable strings on*/ #define ESTRINGS 1 #endif #ifndef EDEBUG #define EDEBUG 0 /*By default, turn ESTRINGS "compliment" condition off */ #endif /*Used internally by the ENUM macro*/ #ifdef ENUM_STR #undef ENUM_STR #endif #define ENUM_STR(r, data, elem) BOOST_PP_STRINGIZE(elem) #define ENUM(name, start, entries) \ BOOST_PP_SEQ_ENUM( \ BOOST_PP_IIF(ENUMS, \ (typedef enum{ BOOST_PP_SEQ_HEAD(entries) = start) \ BOOST_PP_SEQ_TAIL(entries) \ (LAST_##name } name;) \ , \ (static void PP_NILFUNC();) \ ) \ ) \ BOOST_PP_SEQ_ENUM( \ BOOST_PP_IIF(BOOST_PP_BITOR(EDEBUG,ESTRINGS), \ (static const char* name##_Str[]={ BOOST_PP_STRINGIZE(BOOST_PP_SEQ_HEAD(entries)) ) \ BOOST_PP_SEQ_TRANSFORM(ENUM_STR, _, BOOST_PP_SEQ_TAIL(entries) ) \ (};) \ , \ (static void PP_NILFUNC();) \ ) \ ) Now, as I think you pointed out yourself, you can't place the BOOST_PP_SEQ_ENUM inside of a BOOST_PP_EXPR_IIF statement like this: #define ENUM(name, start, entries) \ BOOST_PP_EXPR_IIF(ENUMS)( \ BOOST_PP_SEQ_ENUM( \ (typedef enum { BOOST_PP_SEQ_HEAD(entries) = start) \ BOOST_PP_SEQ_TAIL(entries) \ (LAST_ ## name } name;) \ ) \ ) \ So, what I've shown you in the printable enum above was the only solution I could think of to achieve the result: i.e. a **single** ENUM macro definition that permitted the printable strings *AND* the enums themselves to be conditionally compileable. On the other hand, I'm intrigued with what you presented here: #define ENUM(name, start, entries) \ BOOST_PP_IIF( \ ENUMS, \ BOOST_PP_SEQ_ENUM, BOOST_PP_TUPLE_EAT(1) \ )( \ (typedef enum { BOOST_PP_SEQ_HEAD(entries) = start) \ BOOST_PP_SEQ_TAIL(entries) \ (LAST_ ## name } name;) \ ) \ I didn't pay attention to BOOST_PP_TUPLE_EAT when I was (frantically) trying to make a printable enum. Perhaps it is a means by which I can get rid of the "hack" I described earlier? It sure looks like it will work! Oh, by the way, I was so pleased with the printable enum - I was actually thinking of submitting it for inclusion into Boost. Would a submission like that be more nuisance than benefit? Thanks, -Brent

-----Original Message----- From: boost-bounces@lists.boost.org [mailto:boost-bounces@lists.boost.org] On Behalf Of Arias Brent-P96059
I very much appreciate your answer. And ultimately this hasn't become a big deal, since - as you saw - I found a way around the problem all the same.
Yes.
But now let me answer a very good question you asked:
#define ENUM(name, start, entries)\ BOOST_PP_SEQ_ENUM( \ BOOST_PP_IIF(ENUMS, \ (typedef enum{ BOOST_PP_SEQ_HEAD(entries) = start) \ BOOST_PP_SEQ_TAIL(entries) \ (LAST_##name } name;) \ , \ (static void PP_NILFUNC();) \ ) \ )
Why are you doing the test *inside* of the invocation of SEQ_ENUM?
The short answer: I wanted a **single** ENUM macro definition that permitted the printable strings *AND* the enums themselves to be conditionally compileable.
I think my intention will make more sense if I show you the entire printable enum. It looks like this:
I understand you're reasoning. The point I was making is, though preprocessor metaprogramming is very different from programming in most languages, there are still basic notions of computation, etc., such as control flow--which is nothing but a conditional "invocation" of its accompanying code. Those kinds of things still apply at the preprocessor level. What you really needed was a way to conditionally enumerate some sequence elements, not enumerate a conditional sequence.
Now, as I think you pointed out yourself, you can't place the BOOST_PP_SEQ_ENUM inside of a BOOST_PP_EXPR_IIF statement like this:
#define ENUM(name, start, entries) \ BOOST_PP_EXPR_IIF(ENUMS)( \ BOOST_PP_SEQ_ENUM( \ (typedef enum { BOOST_PP_SEQ_HEAD(entries) = start) \ BOOST_PP_SEQ_TAIL(entries) \ (LAST_ ## name } name;) \ ) \ ) \
You can do it, but EXPR_IIF does not lazily evaluate its argument (the syntax above is what EXPR_IIF would look like if it *did* lazily evaluate it argument). In other words, when ENUMS is 0, SEQ_ENUM will still be invoked, but its results will be discarded. For something like SEQ_ENUM, which is a cheap operation, that is no big deal provided the call is still valid (even though the results are discarded, it can still produce errors if the input is invalid). Other constructs are significantly more expensive.
So, what I've shown you in the printable enum above was the only solution I could think of to achieve the result: i.e. a **single** ENUM macro definition that permitted the printable strings *AND* the enums themselves to be conditionally compileable.
On the other hand, I'm intrigued with what you presented here:
#define ENUM(name, start, entries) \ BOOST_PP_IIF( \ ENUMS, \ BOOST_PP_SEQ_ENUM, BOOST_PP_TUPLE_EAT(1) \ )( \ (typedef enum { BOOST_PP_SEQ_HEAD(entries) = start) \ BOOST_PP_SEQ_TAIL(entries) \ (LAST_ ## name } name;) \ ) \
I didn't pay attention to BOOST_PP_TUPLE_EAT when I was (frantically) trying to make a printable enum. Perhaps it is a means by which I can get rid of the "hack" I described earlier? It sure looks like it will work!
Yes, you can certainly get rid of the hack. The above is equivalent, sans the hack, to the code that you posted previously. The above is a higher-order construct. The IIF is effectively returning a function. One of those functions simply eats its argument. This is not abnormal in preprocessor code (to pass around macro names as arguments).
Oh, by the way, I was so pleased with the printable enum - I was actually thinking of submitting it for inclusion into Boost. Would a submission like that be more nuisance than benefit?
I don't know. I've used such things before (unsurprisingly, only when debugging), but it isn't high on my priority list. If you use enumerations with accompanying "print" functions often, then it certainly pays to generalize the implementation. Have you seen http://www.cuj.com/documents/s=8470/cujboost0306besser/? There is an extended enumeration proposal also (http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2004/n1579.pdf), but I don't know if it includes support for symbolic I/O. I'd read it to find out, but that website is amazingly slow recently. Regards, Paul Mensonides
participants (2)
-
Arias Brent-P96059
-
Paul Mensonides