|
Boost Users : |
From: Paul Mensonides (pmenso57_at_[hidden])
Date: 2005-10-10 16:15:57
> -----Original Message-----
> From: boost-users-bounces_at_[hidden]
> [mailto:boost-users-bounces_at_[hidden]] On Behalf Of Rush Manbert
> I posted this question to comp.lang.c++.moderated and got a
> single reply that basically said "it looks like you need to
> use macros", but I thought I would ask the same question
> here, just in case you MPL folks have some tricks up your
> boost library sleeves.
Just so you know, many Boost libraries, including the MPL, make extensive use of
macros for code generation purposes.
> 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.
> the
> macro-that-is-a-list-of-macros is confusing,
It is actually fairly straightforward.
> 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.
> My question is this: Is there any method available in C++
> that can let me do away with the macros while preserving the
> nice quality that only one data structure needs to be
> maintained?
Only the preprocessor can do the stringizing. You can't initialize an array
statically with templates (unless you know the exact size). If that isn't an
absolute requirement, you can do the rest with templates.
> Something sophisticated and tricky with templates
> perhaps? I expect that the fact that I stringize the enum
> name when creating the lookup table makes a macro the only
> choice. But, since that is only one component in each lookup
> table entry in the real code, I might be willing to give it
> up in order to lose the macros.
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). For something like this, I'd go with
the preprocessor. It is simple and direct--you have some code that needs to be
written (and maintained) in accordance with a dataset, but you don't want to
write the code manually (and, more importantly, maintain manually). Therefore,
let the preprocessor automate the writing. It really is straightforward--the
preprocessor is just writing what you otherwise would be writing by hand.
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