Interpreting #define statement

P

psundara

Hi,

I'm facing a peculiar problem of finding a way to interpret header
information in a smart way.

I have this header file that is shared by many users, which contains,
among things, a few #define statements that associate GUIDs wih a
friendly name. For e.g. consider the file zoo.h:

....
#define tiger GUID1
#define lion GUID2
#define striped_cat tiger
....

This file can be updated - i.e. #define statements are
added/removed/modified.

Now, I want to accept the animal type as input from the user, switch
based on the GUID, and print animal specific information to the user.
Is it posible for me to have a user specify the animal type as name
(i.e. tiger, lion etc.) instead of GUID? It would make it very
convenient to the user.

I have a few ideas, but they don't seem to be very elegant:

1. Have the user specify name-to-GUID mappings in a separate file.

2. Parse zoo.h and do create a string-to-GUID internally. However this
is quite cumbersome as #define statements occur all over the place in
different formats.

Any pointers in this regard will be greatly appreciated!

Thanks,
Palani
 
C

Chinchilla

I don't think using the preprocessor to define aliases for the user is
elegant to begin with. If you want to make it friendly for the user and
easier for you to update what you can do is use your idea of having a
name-to-GUID mapping in a seperate file, and make a simple interface
which the user can freely translate between name's and GUID's.
ex:
_GUID ntoguid(const char*);

than the user can do something like ntoguid("lion"); and it'll return
the correct one.

It entirely depends on what you want to do. I personally would force
users to memorize things. :)
 
M

mlimber

Hi,

I'm facing a peculiar problem of finding a way to interpret header
information in a smart way.

I have this header file that is shared by many users, which contains,
among things, a few #define statements that associate GUIDs wih a
friendly name. For e.g. consider the file zoo.h:

...
#define tiger GUID1
#define lion GUID2
#define striped_cat tiger
...

This file can be updated - i.e. #define statements are
added/removed/modified.

Now, I want to accept the animal type as input from the user, switch
based on the GUID, and print animal specific information to the user.
Is it posible for me to have a user specify the animal type as name
(i.e. tiger, lion etc.) instead of GUID? It would make it very
convenient to the user.

You can use a standard map to associate the two (I'll assume your GUIDs
are ints):

#include <map>
#include <string>
#include <cassert>
#include "guid.h" // Your GUIDs in here

namespace
{
std::map<std::string,int> zooMap;
}

void InitMap()
{
zooMap[ "Lion" ] = GUID1;
zooMap[ "Tiger" ] = GUID2;
// ...
}

// Use the map elsewhere in the file
void Foo( const std::string& name )
{
// Make sure map is initialized
assert( map.size() != 0 );

// Lookup name; might want to use map<>::find() for error checking
const int id = zooMap[ name ];
// ...
}

Alternately, an OO approach might use a factory a la _Modern C++
Design_'s Factory (library source at sourceforge.net/projects/loki-lib
):

#include <iostream>
#include <string>
#include <memory> // for auto_ptr
#include "loki/Singleton.h"
#include "loki/Factory.h"

using namespace std;
using namepsace Loki;

struct Animal
{
virtual ~Animal() {}
virtual void Print( ostream& ) = 0;
};

struct Lion : Animal
{
void Print( ostream& ) { /* ... */ }
};

struct Tiger : Animal
{
void Print( ostream& ) { /* ... */ }
};

// Make the factory a singleton since there should be only one.
typedef Singleton< Factory<Animal, string> > theAnimalFactory;

// Register all our particular animals
namespace
{
Animal CreateLion() { return new Lion; }
Animal CreateTiger() { return new Tiger; }

const bool lionRegistered = theAnimalFactory::Instance()
.Register( "Lion", CreateLion );

const bool tigerRegistered = theAnimalFactory::Instance()
.Register( "Tiger", CreateTiger );
}

// User takes over management of the animal
auto_ptr<Animal> PrintAnimal( const string id )
{
auto_ptr<Animal> animal( theAnimalFactory.CreateObject( id ) );
animal->Print( cout );
return animal;
}

Factory is in essence a snazzy front end for a map because it
associates an ID of some type with a creation function.
I have a few ideas, but they don't seem to be very elegant:

1. Have the user specify name-to-GUID mappings in a separate file.

This idea makes it sound like the list can change at run-time or start
time, independent of the program (e.g., the user can add new animals).
If that's so, you cannot use a static list in a .h file to begin with.
You'll want to use some sort of config file (e.g., .ini file on
Windows). Then you build your map or register with factory as the
program is starting up (or as the user makes changes). See the code
above; the map/factory can be updated at any point during program
operation.
2. Parse zoo.h and do create a string-to-GUID internally. However this
is quite cumbersome as #define statements occur all over the place in
different formats.

It sounds you are suggesting that your C++ program would parse the .h
file to create a map between IDs and strings. This is a bad idea,
especially if the list is changeable by the user. Prefer a file format
that is simpler, as suggested above.
Any pointers in this regard will be greatly appreciated!

Thanks,
Palani

Cheers! --M
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,055
Latest member
SlimSparkKetoACVReview

Latest Threads

Top