As Neil said, I never faced the problem myself. I have faced the issue with codesets though (ie mapping from a string to an enum, and back).
My first reaction is epidermic: DRY.
As you noted, maintaining two enums and the translation takes time, so it's better to refactor and use only one.
My second reaction would be to try and remove the enum. I don't like enums. Perhaps I'll appreciate them with the upcoming C++0x, but as it stands they're more trouble than they are worth in my mind. I prefer smart objects, with categories, etc...
But then, the problem itself is amusing I guess. So if you like to deal with this messy situation, I might as well try to ease your burden.
Templates can't do much here. I've used them for range checking on enums and for string conversion (back and forth) and iterations, but that's all they can do. However as you suspected it's possible with some "subtle" application of Boost.Preprocessor.
What you'd like to write:
DEFINE_CORRESPONDING_ENUMS(Server, Client,
((Server1, 1, Client1, 6))
((Server2, 2, Client2, 3))
((Common1, 4, Common1, 4))
((Common2, 5, Common2, 5))
((Server3, 7, Client3, 1))
);
And we would like it to generate:
struct Server
{
enum type { Server1 = 1, Server2 = 2, Common1 = 4, Common2 = 5, Server3 = 7 };
};
struct Client
{
enum type { Client1 = 6, Client2 = 3, Common1 = 4, Common2 = 5, Client3 = 1 };
};
Server::type ServerFromClient(Client::type c)
{
switch(c)
{
case Client1: return Server1;
//...
default: abort();
}
}
Client::type ClientFromServer(Server::type s)
{
//...
}
The good news is, this is possible. I could even do it, though I'll probably let you work on it a bit ;)
Here are some explanations:
- The third element of the macro is a sequence. A sequence is of unbounded size.
- Each element of the sequence is a 4-tuple. You need to know its size in advance, thus the repetition for
Common
. If you used a sequence instead, you could deal with a variable number of elements (for example to avoid repeating the common...) but it would make things much more complicated
- You'll need to look at
BOOST_PP_SEQ_FOREACH
, it'll be the basic operation here.
- Don't forget
BOOST_PP_CAT
to handle concatenation of tokens.
- on
gcc
the -E
option yields the preprocessor output, it may come handy...
- don't forget comments and how to use in the file, your colleagues will hate you otherwise