Boost logo

Boost Users :

From: Rush Manbert (rush_at_[hidden])
Date: 2005-10-10 13:08:40


Hi all,

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. Basically,
I need to make an enum and a static array of structures from one
data set and I only know one way to do it, and it involves an amount
of "trickiness" that some find disturbing.

The original post:

In the code shown below, the CODE_TABLE macro is used to insert a
sequence of CODE(codeValue) macros. By changing the definition of
CODE(codeValue) right before each usage of CODE_TABLE, I can create
an enumeration of codeValues, then use the same CODE_TABLE definition
to create a static lookup table that can be used to find information
about a codeValue, given its numeric value. In this case, I am finding
the name of the enumerated value. In the real application, there
are a number of other fields available. (As you can probably tell, I
have written a lot of C code in my time.)

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, the macro-that-is-a-list-of-macros
is confusing, 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.

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? 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.

Here is the code example.
Contents of foo.h:
-----------------
#define CODE_TABLE \
     CODE(FooCodeA) \
     CODE(FooCodeB)

#define CODE(codeValue) codeValue,

class foo
{
public:
     typedef enum
     { // Here comes the first use of CODE_TABLE
         CODE_TABLE
     } CodesT;

     foo (CodesT theCode) : m_code (theCode) {}
     const char *lookup (void) const;
     const int getCode (void) const {return m_code;}

private:
     CodesT m_code;

     typedef struct
     {
         CodesT theCode;
         const char *pTheCodeAsString;
     } CodeLookupTableT;
     static CodeLookupTableT m_lookupTable[];

};

Contents of foo.cpp:
-------------------
#include "foo.h"

// Now we redefine CODE so that we can initialize the
// static lookup table
#undef CODE
#define CODE(codeValue) {codeValue, #codeValue},

foo::CodeTableLookupT foo::m_lookupTable[] = { CODE_TABLE };

// The lookup method that finds the string description
// from the numeric code
const char *foo::lookup (void) const {
     for (int i = 0;
          i < (sizeof m_lookupTable)/(sizeof m_lookupTable[0]);
          ++i) {
         if (m_lookupTable[i].theCode == m_code)
             return m_lookupTable[i].pTheCodeAsString;
     }
     return "Unknown code value";

}

contents of main.cpp:
-------------------
#include <iostream>
#include "foo.h"

using namespace std;

int main (int argc, char * const argv[])
{
     foo myFoo (foo::FooCodeB);
     cout << "myFoo with code number....: " << myFoo.getCode() << endl
          << " looks up the code name as: " << myFoo.lookup() << endl;
     return 0;

}

Output from running the program:
-------------------------------

myFoo with code number....: 1
  looks up the code name as: FooCodeB

Thanks,
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