You could use some kind of factory. Search google for "factory pattern c++".
Some simple example code to explain it:
enum TypeCode { FOO, BAR, ... };
void* makeInstance( TypeCode t ) {
switch( t ) {
case FOO: return new FooStruct;
case BAR: return new BarStruct;
...
}
}
void* makeArray( TypeCode t, size_t len ) {
switch( t ) {
case FOO: return new FooStruct[len];
case BAR: return new BarStruct[len];
...
}
}
EDIT Example OOP-style mapping of TypeCode
to some functionality and type description:
// base class .. you may add common functionality
class TypeTraitBase {
public:
virtual void* newStruct() const = 0;
virtual void* newArray( size_t len ) const = 0;
virtual size_t getSize() const = 0;
virtual TypeCode getCode() const = 0;
// add whatever else you need.. e.g.
virtual bool isNumeric() const { return false; }
};
template <TypeCode TCode, typename TStruct>
class TypeTrait : public TypeTraitBase {
public:
virtual TStruct* newStruct() const { return new TStruct; }
virtual TStruct* newArray( size_t len ) const { return new TStruct[len]; }
virtual size_t getSize() const { return sizeof(TStruct); }
virtual TypeCode getCode() const { return TCode; }
};
/* OPTIONAL...
// you may add specializations for some types
// - though it is required only if you want something like isNumeric(),
// - newStruct, newArray and so on do not require specializations!
template < INTEGER, IntegerStruct >
class TypeTrait : public TypeTraitBase {
public:
virtual TStruct* newStruct() const { return new IntegerStruct; }
virtual TStruct* newArray( size_t len ) const { return new IntegerStruct[len]; }
virtual size_t getSize() const { return sizeof(IntegerStruct); }
virtual TypeCode getCode() const { return INTEGER; }
virtual bool isNumeric() const { return true; }
};
*/
class TypeTraitMgr {
static std::map<TypeCode,TypeTraitBase*> traits;
public:
static void reg( TypeTraitBase* tt ) { traits[tt->getCode()] = tt; }
static void cleanup() { /* delete all TypeTraits in traits */ }
static TypeTraitBase* get( TypeCode code ) { return traits[code]; }
};
// in .cpp file: instantiate the static member:
std::map<TypeCode,TypeTraitBase*> traits;
// somewhere before you use it, register all known types:
TypeTraitMgr::reg( new TypeTrait<FOO,YourFOOStruct> );
TypeTraitMgr::reg( new TypeTrait<BAR,YourBARStruct> );
// use it...
void* foo = TypeTraitMgr::get( FOO )->newStruct();
size_t size_of_foo = TypeTraitMgr::get( FOO )->getSize();
// on shutdown, cleanup type traits (they were allocated on heap, delete required)
TypeTraitMgr::cleanup();
This code was not tested, it may contain bugs ;)
Note, that this solution has some overhead of virtual function calls and the like. But its acceptable.
Also, it may be a good idea to merge TypeTraits directly into you structs. This will result in less typing, less code, less overhead.