How to perform type scanning in C++?
I have an ESB. Any serialized message transports its own fully qualified name (that is, namespace + class name). I have a concrete type for each message that encapsulates a specific logic to be executed.
Every time I receive a message, I need to deserialize it at first, so I can perform its operation开发者_JAVA百科s --once more, depending on its concrete type--.I need a way to register every single class at compile time or during my application initialization.
With .net I would use reflection to scan assemblies and discover the message types during initialization, but how would you do it in C++?C++ has no reflection capability. I suppose you could try to scan object files, etc., but there's no reliable way to do this (AFAIK); the compiler may entirely eliminate or mangle certain things.
Essentially, for serialization, you will have to do the registration (semi-)manually. But you may be interested in a serialization library that will help out with the chores, such as Boost Serialization.
Since there is no reflection in C++, I would suggest using an external script to scan your source code for all relevant classes (which is easy if you use empty dummy #defines to annotate them in the source code) and have it generate the registration code.
I personally use the manual registration road. If you forget to register... then the test don't work anyway.
You just have to use a factory, and implement some tag dispatching. For example:
typedef void (*ActOnMessageType)(Message const&);
typedef std::map<std::string, ActOnMessageType> MessageDispatcherType;
static MessageDispatcherType& GetDispatcher() {
static MessageDispatcherType D; return D;
}
static bool RegisterMessageHandler(std::string name, ActOnMessageType func) {
return GetDispatcher().insert(std::make_pair(name, func)).second;
}
Then you just prepare your functions:
void ActOnFoo(Message const& m);
void ActOnBar(Message const& m);
And register them:
bool const gRegisteredFoo = RegisterMessageHandler("Foo", ActOnFoo);
bool const gRegisteredBar = RegsiterMessageHandler("Bar", ActOnBar);
Note: I effectively use a lazily initialized Singleton, in order to allow decoupling. That is the registration is done during the library load and thus each Register...
call is placed in the file where the function is defined. The one difference with a global variable is that here the dispatching map is actually constant once the initialization ends.
精彩评论