You are more than welcome to look at my factory code, it makes heavy
use of Boost ( which is a good thing). There are actualy 3 factories.
One returning new objects derived from a base class, and the base class
must have a typelist to identify the constructor to be used by the
factory.
The second returns a reference to a shared, static object, again the
base class must have a typelist identifying the signature of the
constructor.
The third Factory produces derived objects of a given base class, but
queries the derived objects for a typelist so it can work out which
consructor to call to produce the object.
I'll first pate in the main.cpp, it shoes example code using the
factory, followed by the factory code.
-------------------------------------------------------------------------------------------------------------------------------
<main.cpp>
#include<vector>
#include<iostream>
#include"Factory.h"
#include"Phactory.h"
using namespace std;
struct MyClassVoid {
typedef boost::mpl::list<> Constructor_TypeList;
MyClassVoid(){}
virtual void f()const=0;
virtual ~MyClassVoid(){};
};
struct MyClassVoidDerived
ublic MyClassVoid {
MyClassVoidDerived(){}
virtual void f()const{cout << " I am in MyClassVoidDerived \n";}
virtual ~MyClassVoidDerived(){};
};
namespace {
Registra<MyClassVoid,MyClassVoidDerived>
theRegistraVoid(std::string("MyClassVoidDerived"));
}
struct MyClassDouble {
typedef boost::mpl::list<double> Constructor_TypeList;
typedef boost::mpl::list<double> variant_type_list;
MyClassDouble(double){}
virtual void f(){cout << " I am in MyClassDouble \n";}
virtual ~MyClassDouble(){};
};
struct MyClassDoubleDerived
ublic MyClassDouble {
typedef boost::mpl::list<double> constructor_signature_typelist;
MyClassDoubleDerived(double x):MyClassDouble(x){}
virtual void f(){cout << " I am in MyClassDoubleDerived \n";}
virtual ~MyClassDoubleDerived(){};
};
namespace {
Registra<MyClassDouble,MyClassDouble>
theRegistra(std::string("MyClassDouble"));
Registra<MyClassDouble,MyClassDoubleDerived>
theRegistraD(std::string("MyClassDoubleDerived"));
}
struct MyClassMultiple {
typedef
boost::mpl::list said:
MyClassMultiple(std::string,std::vector<double>,double,MyClassDoubleDerived){}
virtual void f(){cout << " I am in MyClassMultiple \n";}
virtual ~MyClassMultiple(){};
};
namespace {
Registra<MyClassMultiple,MyClassMultiple>
theRegistraM(std::string("MyClassMultiple"));
StaticRegistra<MyClassMultiple,MyClassMultiple>
theStaticRegistraM(std::string("MyClassMultiple"),std::string("String"),std::vector<double>(2),1.0,MyClassDoubleDerived(1.0));
}
struct Dummy{};
struct Base {
typedef boost::mpl::list<double,int,unsigned
long,std::string,std::vector<double>,float,Dummy> variant_type_list;
Base(){}
virtual void f()const=0;
virtual ~Base(){};
};
struct Derived
ublic Base {
typedef boost::mpl::list<double,int,std::string,std::vector<double> >
constructor_signature_typelist;
Derived(double x_,int n_,const std::string &s_,const
std::vector<double>&v_):
x(x_),n(n_),s(s_),v(v_){}
virtual void f()const{
cout << "My Double is " << x << "\n"
<< "My int is " << n << "\n"
<< "My String is " << s << "\n"
<< "My Vector Size is " << v.size() << "\n";
}
private:
double x;
int n;
std::string s;
std::vector<double> v;
};
namespace {
const char * theVarNames[]={"Double","Int","String","Vector"};
PhRegistra<Base,Derived>
thePhRegistra(std::string("DerivedObject"),PARAM_NAMES(theVarNames));
}
int main() {
boost::shared_ptr said:
::instance().RetrieveObject("MyClassVoidDerived"));
thePtrVoid->f();
boost::shared_ptr said:
::instance().RetrieveObject("MyClassDoubleDerived",1.0));
thePtrDoubleDerived->f();
boost::shared_ptr said:
::instance().RetrieveObject("MyClassDouble",1.0));
thePtrDouble->f();
boost::shared_ptr said:
::instance().RetrieveObject("MyClassMultiple",std::string("String"),std::vector<double>(2),1.0,MyClassDoubleDerived(1.0)));
thePtrM->f();
boost::shared_ptr said:
::instance().RetrieveObject("MyClassMultiple"));
thePtrSM->f();
std::map<std::string,typename boost::make_variant_over<typename
Base::variant_type_list::type>::type> theMap;
theMap["Double"]=1.0;
theMap["Int"]=1;
theMap["String"]="hello";
theMap["Vector"]=std::vector<double>(10);
boost::shared_ptr said:
::instance().RetrieveObject("DerivedObject",theMap));
thePtrPhM->f();
}
-------------------------------------------------------------------------------------------------------------------------------------
The Factory code
---------------------------------------------------------------------------
<Singleton.h>
#ifndef SINGLETON_HEADER_GUARD
#define SINGLETON_HEADER_GUARD
#include <boost/utility.hpp>
template<class Object>
struct Singleton :boost::noncopyable{
public:
static Object & instance(){static Object theObject;return theObject;}
virtual ~Singleton(){}
};
#endif
--------------------------------------------------------------------------------------
<Factory.h>
#ifndef FACTORY_HEADER_GUARD
#define FACTORY_HEADER_GUARD
#include<string>
#include<map>
#include"Singleton.h"
#include<boost/shared_ptr.hpp>
#include<boost/mpl/size.hpp>
#include<boost/mpl/list.hpp>
#include<boost/mpl/at.hpp>
#include<boost/preprocessor/repetition.hpp>
#include<boost/preprocessor/arithmetic/sub.hpp>
#ifndef MAX_FACTORIES
#define MAX_FACTORIES 10
#endif
// One Registration object per class in a hireachy, this is the
template blue print for the base classes of
// the registration objects
template
<
class BaseClass,
typename Key = std::string,
unsigned long = boost::mpl::size<typename
BaseClass::Constructor_TypeList>::valuestruct RegistraBase {};
// This is the template blue print for the concrete classes of
// the registration objects
template
<
class BaseClass,
class Derived,
typename Key = std::string,
unsigned long n = boost::mpl::size<typename
BaseClass::Constructor_TypeList>::valuestruct Registra
ublic RegistraBase<BaseClass,Key,n>{};
// This is the factory template blue print of the Factory class
template
<
class BaseClass,
typename Key = std::string ,
unsigned long n = boost::mpl::size<typename
BaseClass::Constructor_TypeList>::valueclass Factory {};
//Helper Macros
#define PARAM(z,Nb,data) typename boost::mpl::at_c<typename
BaseClass::Constructor_TypeList,Nb>::type P##Nb
#define REGISTRABASE(z,Nb,data) \
template<class BaseClass,typename Key> struct
RegistraBase<BaseClass,Key,Nb> { \
virtual boost::shared_ptr<BaseClass>
RetrieveObject(BOOST_PP_ENUM(Nb,PARAM,~))const=0; \
};
BOOST_PP_REPEAT(MAX_FACTORIES,REGISTRABASE,~)
#define FACTORY(z,Nb,data) \
template \
< \
class BaseClass, \
typename Key \
class Factory<BaseClass,Key,Nb> { \
public: \
bool Register(const Key & theKey,RegistraBase<BaseClass,Key,Nb>
*theRegistra){ \
return
theInnerMap.insert(InnerMap::value_type(theKey,theRegistra)).second; \
} \
\
boost::shared_ptr<BaseClass> RetrieveObject(const Key &id
BOOST_PP_COMMA_IF(Nb) BOOST_PP_ENUM(Nb,PARAM,~))const { \
InnerMapIterator theIterator (theInnerMap.find(id)); \
if(theIterator==theInnerMap.end())return
boost::shared_ptr<BaseClass>(static_cast<BaseClass *>(0)); \
return theIterator->second->RetrieveObject(
BOOST_PP_ENUM_PARAMS(Nb,P)); \
} \
private: \
typedef typename std::map<Key,RegistraBase<BaseClass,Key,Nb> *>
InnerMap; \
typedef typename std::map<Key,RegistraBase<BaseClass,Key,Nb>
*>::const_iterator InnerMapIterator; \
std::map<Key,RegistraBase<BaseClass,Key,Nb> *>
theInnerMap; \
};
BOOST_PP_REPEAT(MAX_FACTORIES,FACTORY,~)
// The macro defintions of the Registration Objects
#define REGISTRA(z,Nb,data) \
template<class BaseClass,class Derived,typename
Key> \
struct Registra<BaseClass,Derived,Key,Nb>
ublic
RegistraBase said:
::instance().Register(theKey,this);} \
boost::shared_ptr<BaseClass>
RetrieveObject(BOOST_PP_ENUM(Nb,PARAM,~))const \
{return boost::shared_ptr<BaseClass>(new Derived(
BOOST_PP_ENUM_PARAMS(Nb,P)));} \
virtual ~Registra(){} \
};
BOOST_PP_REPEAT(MAX_FACTORIES,REGISTRA,~)
#undef MAX_FACTORIES
#undef PARAM
#undef REGISTRA
#undef REGISTRABASE
#undef FACTORY
#include"StaticFactory.h"
#endif
-----------------------------------------------------------------------------------------------------------------------------
<StaticFactory.h>
#ifndef STATIC_FACTORY_HEADER_GUARD
#define STATIC_FACTORY_HEADER_GUARD
#include<string>
#include<map>
#include"Singleton.h"
#include<boost/shared_ptr.hpp>
#include<boost/mpl/size.hpp>
#include<boost/mpl/list.hpp>
#include<boost/mpl/at.hpp>
#include<boost/preprocessor/repetition.hpp>
#include<boost/preprocessor/arithmetic/sub.hpp>
#ifndef MAX_STATIC_FACTORIES
#define MAX_STATIC_FACTORIES 10
#endif
template
<
class BaseClass,
typename Key = std::stringstruct StaticRegistraBase {
virtual boost::shared_ptr<BaseClass> RetrieveObject()const=0;
};
template
<
class BaseClass,
class Derived,
typename Key = std::string,
unsigned long n = boost::mpl::size<typename
BaseClass::Constructor_TypeList>::valuestruct StaticRegistra
ublic StaticRegistraBase<BaseClass,Key>{};
template
<
class BaseClass,
typename Key=std::stringclass StaticFactory {
public:
bool Register(const Key & theKey,StaticRegistraBase<BaseClass,Key>
*theRegistra){
return
theInnerMap.insert(InnerMap::value_type(theKey,theRegistra)).second;
}
boost::shared_ptr<BaseClass> RetrieveObject(const Key &id )const {
InnerMapIterator theIterator (theInnerMap.find(id));
if(theIterator==theInnerMap.end())return
boost::shared_ptr<BaseClass>(static_cast<BaseClass *>(0));
return theIterator->second->RetrieveObject();
}
private:
typedef typename std::map<Key,StaticRegistraBase<BaseClass,Key> *>
InnerMap;
typedef typename std::map<Key,StaticRegistraBase<BaseClass,Key>
*>::const_iterator InnerMapIterator;
std::map<Key,StaticRegistraBase<BaseClass,Key> *> theInnerMap;
};
//Helper Macros
#define PARAM(z,Nb,data) typename boost::mpl::at_c<typename
BaseClass::Constructor_TypeList,Nb>::type P##Nb
#define STATICREGISTRA(z,Nb,data) template<class BaseClass,class
Derived,typename Key> \
struct StaticRegistra<BaseClass,Derived,Key, Nb >
ublic
StaticRegistraBase<BaseClass,Key> \
{ \
StaticRegistra(const Key & theKey BOOST_PP_COMMA_IF(Nb)
BOOST_PP_ENUM(Nb,PARAM,~)): \
theObjectPtr(new Derived(BOOST_PP_ENUM_PARAMS(Nb,P))) \
{ \
Singleton said:
::instance().Register(theKey,this); \
} \
boost::shared_ptr<BaseClass> RetrieveObject()const{return
theObjectPtr;} \
virtual ~StaticRegistra(){} \
private: \
boost::shared_ptr<BaseClass> theObjectPtr; \
};
BOOST_PP_REPEAT(MAX_STATIC_FACTORIES,STATICREGISTRA,~)
#undef MAX_STATIC_FACTORIES
#undef PARAM
#undef STATICREGISTRA
#endif
--------------------------------------------------------------------------------------------------------------
<Phactory.h>
#ifndef PHACTORY_HEADER_GUARD
#define PHACTORY_HEADER_GUARD
#include<string>
#include<map>
#include<cassert>
#include<boost/shared_ptr.hpp>
#include<boost/variant.hpp>
#include<boost/utility.hpp>
#include<boost/static_assert.hpp>
#include<boost/mpl/size.hpp>
#include<boost/mpl/list.hpp>
#include<boost/mpl/at.hpp>
#include<boost/preprocessor/repetition.hpp>
#ifndef MAX_PHACTORIES
#define MAX_PHACTORIES 10
#endif
template<unsigned long i>
struct unsigned_long {enum {value=i};};
template<class BaseClass>
struct PhRegistraBase {
typedef typename boost::make_variant_over<typename
BaseClass::variant_type_list::type>::type variant;
typedef std::map<std::string,variant> ParameterMap;
virtual boost::shared_ptr<BaseClass> RetrieveObject(const std::string
&theKey,const ParameterMap& theMap )const=0;
};
template<class BaseClass>
class Phactory {
public:
typedef typename boost::make_variant_over<typename
BaseClass::variant_type_list::type>::type variant;
typedef std::map<std::string,variant> ParameterMap;
bool Register(const std::string &theKey, const
PhRegistraBase<BaseClass>* theRegistra){
return
theInnerMap.insert(InnerMap::value_type(theKey,theRegistra)).second;
}
boost::shared_ptr<BaseClass> RetrieveObject(const std::string &id,
const ParameterMap & theMap)const {
InnerMapIterator theIterator (theInnerMap.find(id));
if(theIterator==theInnerMap.end())return
boost::shared_ptr<BaseClass>(static_cast<BaseClass *>(0));
return theIterator->second->RetrieveObject(id,theMap);
}
private:
typedef typename std::map<std::string,const PhRegistraBase<BaseClass>
*> InnerMap;
typedef typename std::map<std::string,const PhRegistraBase<BaseClass>
*>::const_iterator InnerMapIterator;
std::map<std::string,const PhRegistraBase<BaseClass> *> theInnerMap;
};
#define PARAM(z,Nb,data) boost::get<const boost::mpl::at_c<signature,
Nb >::type &>(theMap.find(theVarNames[Nb])->second)
#define INNER_RETRIVE_OBJECT(z,Nb,data) \
template said:
(const std::string &theKey,const ParameterMap& theMap) \
const{ \
CheckMap(theMap); \
return boost::shared_ptr<BaseClass>(new DerivedClass(
BOOST_PP_ENUM(Nb,PARAM,~) ) \
); \
}
template
<
class BaseClass,
class DerivedClassclass PhRegistra
ublic PhRegistraBase<BaseClass>{
public:
typedef typename DerivedClass::constructor_signature_typelist
signature;
typedef typename boost::make_variant_over<typename
BaseClass::variant_type_list::type>::type variant;
typedef std::map<std::string,variant> ParameterMap;
enum {ssize = boost::mpl::size<signature>::value};
template<unsigned long i>
PhRegistra(const std::string &theKey, const char
*theVariableNames[],const unsigned_long<i> *p=0)
{
BOOST_STATIC_ASSERT(i==ssize); // Must have ONE variable name for
each paramter of the constructor
for(unsigned long i(0);i<ssize;++i)
theVarNames
=std::string(theVariableNames);
Singleton<Phactory<BaseClass> >::instance().Register(theKey,this);
}
boost::shared_ptr<BaseClass> RetrieveObject(const std::string
&theKey,const ParameterMap& theMap)const{
return InnerRetrieveObject<ssize>(theKey,theMap);
}
template<int i>
boost::shared_ptr<BaseClass> InnerRetrieveObject(const std::string
&theKey,const ParameterMap&)const;
BOOST_PP_REPEAT(MAX_PHACTORIES,INNER_RETRIVE_OBJECT,~)
private:
void CheckMap(const ParameterMap& theMap)const {
assert(theMap.size()==ssize);
for(unsigned long
i(0);i<ssize;++i)assert(theMap.find(theVarNames)!=theMap.end());
}
std::string theVarNames[ssize];
};
#define PARAM_NAMES(n) n ,
static_cast<unsigned_long<sizeof(n)/sizeof(char*)> *>(0)
#undef MAX_PHACTORIES
#undef PARAM
#undef INNER_RETRIVE_OBJECT
#endif
-------------------------------------------------------------------------------------------------------------------------------