Matching from symbolic identifier to class name in C ++ using templates?
Duplicate: Is there a way to create objects from a string containing their class name?
Is there a (better) way in C ++ to map a string identifier to a class name. I suspect there might be a way with templates, but I couldn't find the right way.
For example, if I have multiple messages, each one stores a character in the first byte. Thus, message A12345 will create an instance of class A (), message B12345 will map to class B ().
I have a group of message parsers where each class can parse a message. The problem is that I have to manually create a mapping between the class that parses the given message (for example class A ()) and the message id (for example "A").
This is what I am doing now in code, and I think if there is a good way to eliminate the switch in C ++ (magic patterns?):
Msg * msg;
switch(data[0])
{
case 'A': msg = new A(); break;
case 'B': msg = new B(); break;
...
}
msg->parse(data);
On the side of the note, most of the time the id is actually 2 characters long, so "A1" "B1" and so on. And I use class names the same way to keep track of classes, eg. "A1" can be parsed by class A1 () and so on.
NOTE . This looks like a duplicate of C ++: is there a way to create objects from holdig string with their class name? so I suggest closing this question.
a source to share
As someone else said, this cannot be done with templates (templates are computed at compile time, but your character id is computed at runtime).
You can use a map from id to constructor function. It boils down to this question: Activate objects from a string containing the class name
I recommend that you keep it simple. If a simple switch does it, keep it that way. If you really need to have it extensible, you can still enter some automatic lookup for character IDs and so on.
a source to share
There is no way to do this using templates or anything else; C ++ has no reflection. RTTI can help, but you cannot instantiate a class from its name at runtime (as you could with .NET or Java reflection).
However, you can make it easier with a macro. Assuming you don't need only one character class names (as in your example), you cannot use switch
. Try something like this:
#define CREATE_MSG(t) if(strcmp(data,#t)==0) msg=new t()
// I know CREATE_MSG is not a good name,
//but I couldn't think of something better
Msg *msg;
CREATE_MSG(A);
CREATE_MSG(B);
CREATE_MSG(C);
msg->parse(data);
a source to share
You can have a data structure (like a dictionary, or like an array of pairs) that maps a string id to a static function that creates a class. Sort of:
Msg* createA() { return new A(); }
Msg* createB() { return new B(); }
typedef Msg* (*Pfn_create)();
typedef std::map<char,Pfn_create> MsgMap;
MsgMap s_msgMap;
void initialize()
{
s_msgMap.insert(MsgMap::pair('A',createA));
s_msgMap.insert(MsgMap::pair('B',createB));
}
void dispatch(const Data& data)
{
MsgMap::iterator it = s_msgMap.find(data[0]);
Pfn_create creator = it->second;
Msg* msg = creator();
msg->parse(data);
}
a source to share