From: stephan b. <st...@ei...> - 2003-10-08 09:36:03
|
Consider the following code: (ignoring the missing backslashes on the newlines) #define S11N_CLASSLOADER_REGISTER(SerializableType,NS,ClsName) namespace { static const int classloader_register_ ## ClsName = elib::ClassLoader<SerializableType>::registerSubtype<NS::ClsName>( ((!std::string(# NS).empty()) ? (std::string(# NS)+std::string("::")) : "") +std::string(# ClsName)); } (the string() stuff is to get around some "invalid preprocessing token" BS.) That IS the instantiator function. Well, it's a way to replace it. i realized early this morning that my classloader, even including the DLL-handling code, doesn't have a /single/ cast anywhere in it, nor in the client code which uses it. This property led me to the conclusion that i can exploit that to get rid of the new_XXX() function. And so it is, using an INSTANTIATOR-like macro, we do the following: - Create an anonymous namespace. - Add a const static var. The type of var is unimportant - it's the initialization via the function call which is important. The function call registers a class with the classloader. The classloader's work now looks like this: - got a factory for class C? If so return a new instance. - look for a DLL. Find none? No ? Return NULL. - open the DLL. (Don't DO anything with it, though!) - ask myself again: have we got a factory? If not, return NULL, else a new instance. That's it. Simply opening the DLL will activate the const static vars, which, in turn, modify the classloader. Thus, the classloader checks itself again for factories after opening the DLL. This has a couple significant implications: - Any number of objects can be INSTANTIATORed in the same DLL this way, because the anonymous namespaces protect them from collisions. In theory (untested) the "bogus variables" created by the macro can even have the same name and not worry about multiple definitions, because of the properties of anonymous namespaces. - the new_XXX() function is obsoleted. - the classloader, since we no longer have to use a dlsym()'d pointer, can become 100% cast-free (something which i thought was inherently impossible for a classloader!). - the whole process is compile-time type-safe (not so with dlsym()ing). The magic of templates won't let us get away with attempting to do non-safe conversions. - it is free of the conflict which comes up with like-named classes in different namespaces: new_Bar() for classes foo::Bar and and new_Bar() for bar::Bar. i spent the whole night last night gutting/refactoring most of the in-core template depedencies because i wasn't happy with that node-cast code i wrote last night (the post about "casting" node trees). The node class itself is not a template class any more - only some of the de/ser-related functions are. This means that multiple completely different Serializable hierarchies can now interoperate without having to do any conversions whatsoever. (i've got a small working example of this.) As a happy side effect, library usage has been greatly simplified as well (by removing many cases where the client must use a template parameter to define, e.g., a file format's Serializer). But... now i've gotta rewrite some 10 pages of docs and gawd only knows many screens of API docs :/. -- ----- st...@ei... - http://www.einsurance.de "... NOT because we are America's poodle ..." Tony Blair, 30.9.2003 |