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();

 

}


Send instant messages to your online friends http://uk.messenger.yahoo.com