Boost logo

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