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