M
mlimber
This is a repost (with slight modifications) from
comp.lang.c++.moderated in an effort to get some response.
I am using Loki's Factory as presented in _Modern C++ Design_ for
message passing in an embedded environment with multiple processors. I
created a policy for classes, which, I had hoped, would automatically
register the class with the appropriate factory:
// In some header file...
#include <cassert>
#include "Loki/Singleton.h"
#include "Loki/Factory.h"
#include "Loki/TypeManip.h"
#include "Loki/static_check.h"
// Requirements: ConcreteClass must implement a static method GetID()
template<class AbstractClass, class ConcreteClass>
class DefaultCreationPolicy
{
public:
static AbstractClass* Create()
{
// Verify that the given types are actually super and sub classes
STATIC_CHECK(
SUPERSUBCLASS( AbstractClass, ConcreteClass ),
types_are_not_super_and_subclass
);
assert( m_registered );
return new ConcreteClass;
}
static bool IsRegistered() { return m_registered; }
protected:
DefaultCreationPolicy() {}
~DefaultCreationPolicy() {}
private:
typedef Loki::SingletonHolder<Loki::Factory< AbstractClass, int>
theFactory;
static const bool m_registered; // One per template instantiation
};
// Register all our subclasses with their respective factories.
// (Note that these static members appear in 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>
const bool
DefaultCreationPolicy<AbstractClass,ConcreteClass>::m_registered
= DefaultCreationPolicy<AbstractClass,ConcreteClass>::
theFactory::Instance().Register(
ConcreteClass::GetID(),
ConcreteClass::Create
);
I use this code like this:
template<int id>
struct AssignID
{
static int GetID() { return id; }
};
struct MyBase
{
virtual ~MyBase() {}
};
enum { DERIVED_1, DERIVED_2 };
struct Derived1
: MyBase
, AssignID< DERIVED_1 >
, DefaultCreationPolicy<MyBase,Derived1>
{};
struct Derived2
: MyBase
, AssignID< DERIVED_2 >
, DefaultCreationPolicy<MyBase,Derived2>
{};
In theory, this code should automatically register these two classes
with a MyBase factory so that I can create objects using the factory
like this:
// ...
typedef Loki::SingletonHolder< Loki::Factory<MyBase, int> >
theFactory;
void Foo()
{
try
{
typedef std::auto_ptr<MyBase> Ptr;
Ptr p1( theFactory::Instance().CreateObject( DERIVED_1 ) );
Ptr p2( theFactory::Instance().CreateObject( DERIVED_2 ) );
// ... use p1 and p2 ...
}
catch( const std::exception& e )
{
std::cerr << e.what() << std::endl;
}
}
The problem is that, with just the code above, the
DefaultCreationPolicy<> policy never gets instantiated for Derived1 or
Derived2, and thus either call to Factory<>::CreateObject() will throw
because the classes are not registered. If, however, I manually access
the creation policy somewhere like this:
void Bar()
{
if( Derived1::IsRegistered() && Derived2::IsRegistered() )
{
Foo();
}
}
then, Derived1 and Derived2 *do* get instantiated and registered
automatically as desired.
Can anyone explain why this happens and perhaps suggest a better way of
forcing the instantiation of these classes? I was trying to avoid
manually referencing each of the factory-creatable classes, since in my
real code, it's an annoyance to have to do so -- especially three years
from now when I or someone else will need to add some additional
subclasses to MyBase and will have to remember to manually reference
the creation policy.
Cheers! --M
comp.lang.c++.moderated in an effort to get some response.
I am using Loki's Factory as presented in _Modern C++ Design_ for
message passing in an embedded environment with multiple processors. I
created a policy for classes, which, I had hoped, would automatically
register the class with the appropriate factory:
// In some header file...
#include <cassert>
#include "Loki/Singleton.h"
#include "Loki/Factory.h"
#include "Loki/TypeManip.h"
#include "Loki/static_check.h"
// Requirements: ConcreteClass must implement a static method GetID()
template<class AbstractClass, class ConcreteClass>
class DefaultCreationPolicy
{
public:
static AbstractClass* Create()
{
// Verify that the given types are actually super and sub classes
STATIC_CHECK(
SUPERSUBCLASS( AbstractClass, ConcreteClass ),
types_are_not_super_and_subclass
);
assert( m_registered );
return new ConcreteClass;
}
static bool IsRegistered() { return m_registered; }
protected:
DefaultCreationPolicy() {}
~DefaultCreationPolicy() {}
private:
typedef Loki::SingletonHolder<Loki::Factory< AbstractClass, int>
theFactory;
static const bool m_registered; // One per template instantiation
};
// Register all our subclasses with their respective factories.
// (Note that these static members appear in 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>
const bool
DefaultCreationPolicy<AbstractClass,ConcreteClass>::m_registered
= DefaultCreationPolicy<AbstractClass,ConcreteClass>::
theFactory::Instance().Register(
ConcreteClass::GetID(),
ConcreteClass::Create
);
I use this code like this:
template<int id>
struct AssignID
{
static int GetID() { return id; }
};
struct MyBase
{
virtual ~MyBase() {}
};
enum { DERIVED_1, DERIVED_2 };
struct Derived1
: MyBase
, AssignID< DERIVED_1 >
, DefaultCreationPolicy<MyBase,Derived1>
{};
struct Derived2
: MyBase
, AssignID< DERIVED_2 >
, DefaultCreationPolicy<MyBase,Derived2>
{};
In theory, this code should automatically register these two classes
with a MyBase factory so that I can create objects using the factory
like this:
// ...
typedef Loki::SingletonHolder< Loki::Factory<MyBase, int> >
theFactory;
void Foo()
{
try
{
typedef std::auto_ptr<MyBase> Ptr;
Ptr p1( theFactory::Instance().CreateObject( DERIVED_1 ) );
Ptr p2( theFactory::Instance().CreateObject( DERIVED_2 ) );
// ... use p1 and p2 ...
}
catch( const std::exception& e )
{
std::cerr << e.what() << std::endl;
}
}
The problem is that, with just the code above, the
DefaultCreationPolicy<> policy never gets instantiated for Derived1 or
Derived2, and thus either call to Factory<>::CreateObject() will throw
because the classes are not registered. If, however, I manually access
the creation policy somewhere like this:
void Bar()
{
if( Derived1::IsRegistered() && Derived2::IsRegistered() )
{
Foo();
}
}
then, Derived1 and Derived2 *do* get instantiated and registered
automatically as desired.
Can anyone explain why this happens and perhaps suggest a better way of
forcing the instantiation of these classes? I was trying to avoid
manually referencing each of the factory-creatable classes, since in my
real code, it's an annoyance to have to do so -- especially three years
from now when I or someone else will need to add some additional
subclasses to MyBase and will have to remember to manually reference
the creation policy.
Cheers! --M