
-----Original Message----- From: boost-users-bounces@lists.boost.org [mailto:boost-users-bounces@lists.boost.org] On Behalf Of Rush Manbert
Macros are not evil. Some uses of them are evil; some are not.
I actually agree with you. This was posted to comp.lang.c++.moderated, and they point you to the C++ FAQ first. It states more than once that "Macros are Evil", so I thought I'd avoid getting flamed if I mentioned that. ;-)
Yeah, I know how that goes.
That's pretty cool. I'm going to impose on your good nature to ask a follow up question here. In the real code, each CODE macro contains more entries, like so: #define CODE_TABLE \ CODE(FooCodeA, "FooCodeA short description", "SummarySelectorFooCodeA", "DetailSelectorFooCodeA") \ CODE(FooCodeB, "FooCodeB short description", "SummarySelectorFooCodeB", "DetailSelectorFooCodeB")
And the structure is defined as: typedef struct { CodesT theCode; const char *pTheCodeAsString; const char *pShortDescription; const char *pSummarySelector; const char *pDetailSelector; } CodeLookupTableT;
I have done no programming with the preprocessor lib, so I only have a vague idea how to extend what you did to cover this case. (I think CODE needs to define either an array or a list or a sequence or a tuple, but that's as far as I have gotten...) Would you be willing to give it a go?
Certainly. You just need a have a data structure of data structures. You don't really need CODE at all. -------------------- foo.h -------------------- #include <boost/preprocessor/punctuation/comma_if.hpp> #include <boost/preprocessor/seq/for_each_i.hpp> #include <boost/preprocessor/tuple/elem.hpp> #define CODE_TABLE \ ( (FooCodeA, "description", "summary", "detail") ) \ ( (FooCodeB, "description", "summary", "detail") ) \ /**/ #define ENUM(r, _, i, tuple) \ BOOST_PP_COMMA_IF(i) BOOST_PP_TUPLE_ELEM(4, 0, tuple) \ /**/ class foo { public: typedef enum { BOOST_PP_SEQ_FOR_EACH_I(ENUM, ~, CODE_TABLE) }; // ... }; #undef ENUM -------------------- foo.cpp -------------------- #include "foo.h" #include <boost/preprocessor/punctuation/comma_if.hpp> #include <boost/preprocessor/seq/for_each_i.hpp> #include <boost/preprocessor/stringize.hpp> #define ENTRY(r, _, i, tuple) \ BOOST_PP_COMMA_IF(i) ENTRY_II tuple \ /**/ #define ENTRY_II(code, desc, summary, detail) \ { code, BOOST_PP_STRINGIZE(code), desc, summary, detail } \ /**/ foo::CodeTableLookupT foo::m_lookupTable[] = { BOOST_PP_SEQ_FOR_EACH_I(ENTRY, ~, CODE_TABLE) } #undef ENTRY #undef ENTRY_II Note that I'm using an extra ENTRY_II macro here to avoid five invocations of BOOST_PP_TUPLE_ELEM. With variadic macros (from C99 and hopefully C++0x), it is possible to make the whole thing cleaner. E.g. this is how I might do it in Chaos: #include <chaos/preprocessor/punctuation/comma_if.h> #include <chaos/preprocessor/seq/auto/for_each_i.h> #define CODE_TABLE \ (FooCodeA, "descriptionA", "summaryA", "detailA") \ (FooCodeB, "descriptionB", "summaryB", "detailB") \ /**/ #define ENTRY(s, i, code, desc, summary, detail) \ CHAOS_PP_COMMA_IF(i) { code, #code, desc, summary, detail } \ /**/ // ^^^^^ Chaos guarantees that this will // work; the Boost pp-lib does not. foo::CodeTableLookupT foo::m_lookupTable[] = { CHAOS_PP_SEQ_AUTO_FOR_EACH_I(ENTRY, CODE_TABLE) }; In other words, it is using variadic parameter sets natively. Of course, this is in the not yet realized world of C++ with variadic macros. In real C++ today, you'd have to do something like the sequence of tuples above. (Of course, doing so in Chaos--even without variadics--is still better as it allows argument remapping.) Regards, Paul Mensonides