-----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
#include
#include
#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
#include
#include
#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
#include
#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