m limber
Posts: 3
Nickname: mlimber
Registered: Nov, 2006
|
|
Re: Subscribing Template Classes with Object Factories in C++
|
Posted: Sep 17, 2007 9:57 AM
|
|
Thanks for this. I'd note that there are several syntax errors herein (e.g., "FactorySubscriber_2<C, H1, H2, IPC, Factory, CMW:>:subscribe(f)" should have the ":" after the ">").
I have a perhaps complementary technique that gives automatic registration with Loki factories. Below is a simplified version to ease explanation and understanding that is built with Loki 0.1.6 and MS VC++ 2005.
The key is that each factory-creatable class inherits from my FactoryCreatablePolicy, which automatically registers it with the factory. It comes with a virtual destructor (see notes in the destructor), but considering that we're talking about a hierarchy of classes, the factory-creatable class probably already had a virtual table, so we're not added much.
#include "loki/Factory.h" #include "loki/Singleton.h" #include "loki/static_check.h" #include "loki/TypeManip.h"
template < class AbstractClass, class ConcreteClass, class FactoryIDType > class FactoryCreatablePolicy { public: static AbstractClass* Create() { // Verify that the given types are // actually super and sub classes LOKI_STATIC_CHECK( LOKI_SUPERSUBCLASS( AbstractClass, ConcreteClass ), types_are_not_super_and_subclass );
return new ConcreteClass; }
// Method to allow non-conformant compilers // to manually register with the factory. // Only needed as a work-around. static bool IsRegistered() { return registered_; }
protected: // Protected ctor and dtor so base classes // can use this as a policy FactoryCreatablePolicy() {}
// "virtual" is required because otherwise the compiler // may optimize this away, subverting the trick described // below. virtual ~FactoryCreatablePolicy() { // In order to automatically register with // the factory any subclass that uses this // class as a policy, we must force the // instantiation of the static member // registered_. Otherwise, it will not be // instantiated unless the program explicitly // references it somewhere, which is an // inconvenient requirement. This way it will // always be instantiated on a standard- // conformant compiler.
(void)®istered_; }
private: // This typedef would need to be expanded to // include all other factory parameters. It is // reduced here for the sake of simplicity of // presentation.
typedef Loki::SingletonHolder < Loki::Factory < AbstractClass, FactoryIDType > > theFactory; static const volatile bool registered_; };
// Register all our factory-creatable classes // with their respective factories. (Note that // these static members appear in the header file // because they are themselves templates. The // compiler will ensure that there is only one // instance of each globally.) template < class AbstractClass, class ConcreteClass, class FactoryIDType > const volatile bool FactoryCreatablePolicy<AbstractClass, ConcreteClass, FactoryIDType>::registered_ = theFactory::Instance().Register( ConcreteClass::FACTORY_ID, Create );
Now some code to demonstrate what it does. Given a hierarchy of classes (here, a base with two derived classes), each class must define a class ID for the factory. I have used ints here for simplicity, but it could be strings or whatever.
struct Base { virtual ~Base() {} };
struct Derived1 : Base , FactoryCreatablePolicy<Base,Derived1,int> { enum { FACTORY_ID = 1 }; };
struct Derived2 : Base , FactoryCreatablePolicy<Base,Derived2,int> { enum { FACTORY_ID = 2 }; };
typedef Loki::Factory<Base, int> BaseFactory; typedef Loki::SingletonHolder< BaseFactory > theBaseFactory;
int main() { BaseFactory& factory = theBaseFactory::Instance();
try { auto_ptr<Base> b1( factory.CreateObject( Derived1::FACTORY_ID ) ); auto_ptr<Base> b2( factory.CreateObject( Derived2::FACTORY_ID ) );
// ...
cout << "Successful creation of objects." << endl; } catch( const exception& e ) { cerr << e.what() << endl; return -1; } }
This might be compatible and incorporatable into what you've done here. I've also proposed that the Loki crew consider including code in Loki.
Cheers! --M
PS, Thanks to several folks on comp.lang.c++.moderated, especially James Kanze, for helping me work this out a bit.
|
|