|
Boost Users : |
From: Paul Mensonides (pmenso57_at_[hidden])
Date: 2005-10-12 16:08:25
> -----Original Message-----
> From: boost-users-bounces_at_[hidden]
> [mailto:boost-users-bounces_at_[hidden]] 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
Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net