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.