For the past few months I have been making more and more use of Boost, in fact I would say becoming more and more reliant on Boost, every so often introducing myslef to a new library. But discovering the MPL, well that was awsome. The first time I applied it was to implement a factory. I would NEVR have though of doing it this way WITHOUT the MPL. Any comments on my use ( or indeed abuse !) of Boost would be more than apprieciated.
<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>//Constructors of different Hierachies take a different humber fo parameters , so we set up
//some helper macros, for constructirs taking up to 10 parameters. More can be defined if required
#define
PARAM_0#define
PARAM_1 typename boost::mpl::at_c<typename BaseClass::Constructor_TypeList,0>::type P1#define
PARAM_2 PARAM_1 , typename boost::mpl::at_c<typename BaseClass::Constructor_TypeList,1>::type P2#define
PARAM_3 PARAM_2 , typename boost::mpl::at_c<typename BaseClass::Constructor_TypeList,2>::type P3#define
PARAM_4 PARAM_3 , typename boost::mpl::at_c<typename BaseClass::Constructor_TypeList,3>::type P4#define
PARAM_5 PARAM_4 , typename boost::mpl::at_c<typename BaseClass::Constructor_TypeList,4>::type P5#define
PARAM_6 PARAM_5 , typename boost::mpl::at_c<typename BaseClass::Constructor_TypeList,5>::type P6#define
PARAM_7 PARAM_6 , typename boost::mpl::at_c<typename BaseClass::Constructor_TypeList,6>::type P7#define
PARAM_8 PARAM_7 , typename boost::mpl::at_c<typename BaseClass::Constructor_TypeList,7>::type P8#define
PARAM_9 PARAM_8 , typename boost::mpl::at_c<typename BaseClass::Constructor_TypeList,8>::type P9#define
PARAM_10 PARAM_9 , typename boost::mpl::at_c<typename BaseClass::Constructor_TypeList,9>::type P10
#define
Q0#define
Q1 P1#define
Q2 Q1, P2#define
Q3 Q2, P3#define
Q4 Q3, P4#define
Q5 Q4, P5#define
Q6 Q5, P6#define
Q7 Q6, P7#define
Q8 Q7, P8#define
Q9 Q8, P9#define
Q10 Q9, P10
// 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>::value>
struct
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>::value>
struct
Registra :public 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>::value>
class
Factory {};
// This is the Factory 'concrete' class for Hireachies where the constrcutors tales no parameters
template
<
class
BaseClass,typename
Key>
class
Factory<BaseClass,Key,0> {public
: bool Register(const Key & theKey,RegistraBase<BaseClass,Key,0> *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(Q0);}
private
: typedef typename std::map<Key,RegistraBase<BaseClass,Key,0> *> InnerMap; typedef typename std::map<Key,RegistraBase<BaseClass,Key,0> *>::const_iterator InnerMapIterator;std::map<Key,RegistraBase<BaseClass,Key,0> *> theInnerMap;
};
// This is ta Macro definition Factory 'concrete' class for Hireachies where the constrcutors take
// a non xero number of parameters
#define
FACTORY(NnN) \template
\< \
class BaseClass, \ typename Key \> \
class
Factory<BaseClass,Key,NnN> { \public
: \ bool Register(const Key & theKey,RegistraBase<BaseClass,Key,NnN> *theRegistra){ \ return theInnerMap.insert(InnerMap::value_type(theKey,theRegistra)).second; \} \
\
boost::shared_ptr<BaseClass> RetrieveObject(
const Key &id,PARAM_##NnN )const { \InnerMapIterator theIterator (theInnerMap.find(id)); \
if(theIterator==theInnerMap.end())return boost::shared_ptr<BaseClass>(static_cast<BaseClass *>(0)); \ return theIterator->second->RetrieveObject(Q##NnN ); \} \
private
: \ typedef typename std::map<Key,RegistraBase<BaseClass,Key,NnN> *> InnerMap; \ typedef typename std::map<Key,RegistraBase<BaseClass,Key,NnN> *>::const_iterator InnerMapIterator; \std::map<Key,RegistraBase<BaseClass,Key,NnN> *> theInnerMap; \
};
FACTORY(1)
FACTORY(2)
FACTORY(3)
FACTORY(4)
FACTORY(5)
FACTORY(6)
FACTORY(7)
FACTORY(8)
FACTORY(9)
FACTORY(10)
// The macro defintions of the Registration Objects
#define
REGISTRA(NnN) \template
<class BaseClass,typename Key> struct RegistraBase<BaseClass,Key,NnN> { \ virtual boost::shared_ptr<BaseClass> RetrieveObject(PARAM_##NnN)const=0; \}; \
template
<class BaseClass,class Derived,typename Key> \struct
Registra<BaseClass,Derived,Key,NnN>:public RegistraBase<BaseClass,Key,NnN> { \Registra(
const Key & theKey){Singleton<Factory<BaseClass,Key,NnN> >::instance().Register(theKey,this);} \boost::shared_ptr<BaseClass> RetrieveObject(PARAM_
##NnN)const{return boost::shared_ptr<BaseClass>(new Derived(Q##NnN));} \ virtual ~Registra(){} \};
REGISTRA(0)
REGISTRA(1)
REGISTRA(2)
REGISTRA(3)
REGISTRA(4)
REGISTRA(5)
REGISTRA(6)
REGISTRA(7)
REGISTRA(8)
REGISTRA(9)
REGISTRA(10)
#endif
----------------------------- end of Factory.h
<main.cpp>
#include
<vector>#include
<iostream>#include
"Factory.h"using
namespace std;struct
MyClassVoid { typedef boost::mpl::list<> Constructor_TypeList;MyClassVoid(){}
virtual void f()const=0; virtual ~MyClassVoid(){};};
struct
MyClassVoidDerived :public 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;MyClassDouble(
double){} virtual void f(){cout << " I am in MyClassDouble \n";} virtual ~MyClassDouble(){};};
struct
MyClassDoubleDerived :public MyClassDouble {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<std::string,std::vector<double>,double,MyClassDoubleDerived > Constructor_TypeList;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"));}
int
main() {boost::shared_ptr<MyClassVoid> thePtrVoid(Singleton<Factory<MyClassVoid> >::instance().RetrieveObject(
"MyClassVoidDerived"));thePtrVoid->f();
boost::shared_ptr<MyClassDouble> thePtrDoubleDerived(Singleton<Factory<MyClassDouble> >::instance().RetrieveObject(
"MyClassDoubleDerived",1.0));thePtrDoubleDerived->f();
boost::shared_ptr<MyClassDouble> thePtrDouble(Singleton<Factory<MyClassDouble> >::instance().RetrieveObject(
"MyClassDouble",1.0));thePtrDouble->f();
boost::shared_ptr<MyClassMultiple>
thePtrM(Singleton<Factory<MyClassMultiple> >::instance().RetrieveObject(
"MyClassMultiple",std::string("String"),std::vector<double>(2),1.0,MyClassDoubleDerived(1.0)));thePtrM->f();
}