|
Boost Users : |
From: Nindi Singh (nindi73_at_[hidden])
Date: 2006-11-02 19:05:40
Ok .... as good a time as any other to look at the Preprocessor library. So now my factories look like this.
There still needs to be alot of polishing, error handling etc, but I think I have mad a fair application
of Boost. So I'll post the code taking on board your suggestion for completeness. ( Hopefully NOT in HTML 8-) )
---------------------------------------------------------------------------
<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>::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 {};
//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>:public RegistraBase<BaseClass,Key,Nb> { \
Registra(const Key & theKey){Singleton<Factory<BaseClass,Key,Nb> >::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::string
>
struct 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>::value
>
struct StaticRegistra :public StaticRegistraBase<BaseClass,Key>{};
template
<
class BaseClass,
typename Key=std::string
>
class 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 >:public 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<StaticFactory<BaseClass,Key> >::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<> boost::shared_ptr<BaseClass> InnerRetrieveObject< Nb >(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 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;
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[i])!=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
-----------------------------------------------------------------------------------------------------------------------------------
<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 :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;
typedef boost::mpl::list<double> variant_type_list;
MyClassDouble(double){}
virtual void f(){cout << " I am in MyClassDouble \n";}
virtual ~MyClassDouble(){};
};
struct MyClassDoubleDerived :public 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<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"));
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 :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() {
char ch;
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();
boost::shared_ptr<MyClassMultiple>
thePtrSM(Singleton<StaticFactory<MyClassMultiple> >::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<Base>
thePtrPhM(Singleton<Phactory<Base> >::instance().RetrieveObject("DerivedObject",theMap));
thePtrPhM->f();
cin >>ch;
}
--------------------------------------------------------------------------------------------------------------------------------------
----- Original Message ----
From: David Abrahams <dave_at_[hidden]>
To: boost-users_at_[hidden]
Sent: Thursday, 2 November, 2006 5:33:36 PM
Subject: Re: [Boost-users] Boost ROCKS !!!!!
Nindi Singh <nindi73_at_[hidden]> writes:
> Any comments on my use ( or indeed abuse !) of Boost would be more
> than apprieciated.
You might consider using the preprocessor library to eliminate some of
that repetitive macro code.
--
Dave Abrahams
Boost Consulting
www.boost-consulting.com
_______________________________________________
Boost-users mailing list
Boost-users_at_[hidden]
http://lists.boost.org/mailman/listinfo.cgi/boost-users
___________________________________________________________
The all-new Yahoo! Mail goes wherever you go - free your email address from your Internet provider. http://uk.docs.yahoo.com/nowyoucan.html
Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net