Boost logo

Boost Users :

From: Rush Manbert (rush_at_[hidden])
Date: 2005-10-12 13:07:43


Paul Mensonides wrote:

> IMHO, the benefit of this technique is that you only maintain
>
>>CODE_TABLE. All of the required code bits are generated from
>>it. The downside is that Macros are Evil,
>>
>>
>
>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. ;-)

>>and you need to
>>carefully redefine CODE(codeValue) in the proper locations.
>>Additionally, the real application will have multiple classes
>>that each define their own CODE_TABLE contents, so making it
>>all work correctly is a little tricky.
>>
>>
>
>The only thing that is potentially confusing is the #define/#undef of
>CODE--whose use is hidden behind the the CODE_TABLE interface. It would be
>better, IMO, to get rid of that reliance on a specific name (i.e. "CODE"). E.g.
>
>// foo.h
>#include <boost/preprocessor/seq/enum.hpp>
>
>#define CODE_TABLE (FooCodeA)(FooCodeB)
> // ^^^^^^^^^^
> // Of course, this macro definition should never propogate
> // out of the header unless it is prefixed by a library
> // namespace. I.e. non-local definitions like this one
> // need to be all-caps (which you have, and that's good),
> // but it also needs to be prefixed (by library or program)
> // such as "LIBNAME_CODE_TABLE". Such an unprefixed name
> // should absolutely never be visible outside the location
> // where it is defined. That truly is evil.
>
>class foo
>{
>public:
> typedef enum { BOOST_PP_SEQ_ENUM(CODE_TABLE) } CodesT;
>// ...
>};
>
>// 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, codeValue) \
> BOOST_PP_COMMA_IF(i) { codeValue, BOOST_PP_STRINGIZE(codeValue) } \
> /**/
>
>foo::CodeTableLookupT foo::m_lookupTable[]
> = { BOOST_PP_SEQ_FOR_EACH_I(ENTRY, ~, CODE_TABLE) }
>
>#undef ENTRY
>
>const char *foo::lookup (void) const {
> // ...
>}
>
>The advantage of this is that you make what you are doing with your table of
>codes at particular points explicit.
>
>
>
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?

> There is nothing wrong with using macros for this. You could do most
> of the
>
>above with the template mechanism, but it might very well turn out to be more
>complex (and therefore, more confusing).
>
>
I think you're right about this. Thank you for your help.

- Rush


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