#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>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
CPARAM_1 boost::get<const boost::mpl::at_c<signature,0>::type &>(theMap.find(theVarNames[0])->second)#define
CPARAM_2 CPARAM_1, boost::get<const boost::mpl::at_c<signature,1>::type &>(theMap.find(theVarNames[1])->second)#define
CPARAM_3 CPARAM_2, boost::get<const boost::mpl::at_c<signature,2>::type &>(theMap.find(theVarNames[2])->second)#define
CPARAM_4 CPARAM_3, boost::get<const boost::mpl::at_c<signature,3>::type &>(theMap.find(theVarNames[3])->second)#define
CPARAM_5 CPARAM_4, boost::get<const boost::mpl::at_c<signature,4>::type &>(theMap.find(theVarNames[4])->second)#define
CPARAM_6 CPARAM_5, boost::get<const boost::mpl::at_c<signature,5>::type &>(theMap.find(theVarNames[5])->second)#define
CPARAM_7 CPARAM_6, boost::get<const boost::mpl::at_c<signature,6>::type &>(theMap.find(theVarNames[6])->second)#define
CPARAM_8 CPARAM_7, boost::get<const boost::mpl::at_c<signature,7>::type &>(theMap.find(theVarNames[7])->second)#define
CPARAM_9 CPARAM_8, boost::get<const boost::mpl::at_c<signature,8>::type &>(theMap.find(theVarNames[8])->second)#define
CPARAM_10 CPARAM_9, boost::get<const boost::mpl::at_c<signature,9>::type &>(theMap.find(theVarNames[9])->second)#define
INNER_RETRIVE_OBJECT(Nb) \ template<> boost::shared_ptr<BaseClass> InnerRetrieveObject< Nb >(const std::string &theKey,const ParameterMap& theMap)const{ \CheckMap(theMap); \
return boost::shared_ptr<BaseClass>(new DerivedClass( CPARAM_##Nb ) \); \
}
template
<
class BaseClass, class DerivedClass>
class
PhRegistra:public 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[i]=std::string(theVariableNames[i]);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;INNER_RETRIVE_OBJECT(1)
INNER_RETRIVE_OBJECT(2)
INNER_RETRIVE_OBJECT(3)
INNER_RETRIVE_OBJECT(4)
INNER_RETRIVE_OBJECT(5)
INNER_RETRIVE_OBJECT(6)
INNER_RETRIVE_OBJECT(7)
INNER_RETRIVE_OBJECT(8)
INNER_RETRIVE_OBJECT(9)
INNER_RETRIVE_OBJECT(10)
private
: void CheckMap(const ParameterMap& theMap)const {assert(theMap.size()==ssize);
for(unsigned long i(0);i<ssize;++i)assert(theMap.find(theVarNames[i])!=theMap.end());}
std::string theVarNames[ssize];
};
#define
PARAM_NAMES(n) n , static_cast<unsigned_long<sizeof(n)/sizeof(char*)> *>(0)
#endif
----------------- end of Phactory.h
<main,cpp>
#include
<vector>#include
<iostream>#include
"Phactory.h"using
namespace std;template
<class Object>//Quick liitle singletone just to demonstrate
class
Singleton {public
: static Object & instance(){static Object theObject;return theObject;} virtual ~Singleton(){}private
:Singleton();
Singleton(
const Singleton<Object> & illegal);Singleton<Object> &
operator=(const Singleton<Object> & illegal){return *this;}};
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 :public 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() {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<Base>
thePtrSM(Singleton<Phactory<Base> >::instance().RetrieveObject(
"DerivedObject",theMap));thePtrSM->f();
}