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-) )
---------------------------------------------------------------------------
#ifndef SINGLETON_HEADER_GUARD
#define SINGLETON_HEADER_GUARD
#include
template<class Object>
struct Singleton :boost::noncopyable{
public:
static Object & instance(){static Object theObject;return theObject;}
virtual ~Singleton(){}
};
#endif
--------------------------------------------------------------------------------------
#ifndef FACTORY_HEADER_GUARD
#define FACTORY_HEADER_GUARD
#include<string>
#include<map>
#include"Singleton.h"
#include
#include
#include
#include
#include
#include
#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{};
// 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::type P##Nb
#define REGISTRABASE(z,Nb,data) \
template struct RegistraBase { \
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 { \
public: \
bool Register(const Key & theKey,RegistraBase *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(0)); \
return theIterator->second->RetrieveObject( BOOST_PP_ENUM_PARAMS(Nb,P)); \
} \
private: \
typedef typename std::map *> InnerMap; \
typedef typename std::map *>::const_iterator InnerMapIterator; \
std::map *> theInnerMap; \
};
BOOST_PP_REPEAT(MAX_FACTORIES,FACTORY,~)
// The macro defintions of the Registration Objects
#define REGISTRA(z,Nb,data) \
template \
struct Registra:public RegistraBase { \
Registra(const Key & theKey){Singleton >::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
-----------------------------------------------------------------------------------------------------------------------------
#ifndef STATIC_FACTORY_HEADER_GUARD
#define STATIC_FACTORY_HEADER_GUARD
#include<string>
#include<map>
#include"Singleton.h"
#include
#include
#include
#include
#include
#include
#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{};
template
<
class BaseClass,
typename Key=std::string
class StaticFactory {
public:
bool Register(const Key & theKey,StaticRegistraBase *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(0));
return theIterator->second->RetrieveObject();
}
private:
typedef typename std::map *> InnerMap;
typedef typename std::map *>::const_iterator InnerMapIterator;
std::map *> theInnerMap;
};
//Helper Macros
#define PARAM(z,Nb,data) typename boost::mpl::at_c::type P##Nb
#define STATICREGISTRA(z,Nb,data) template \
struct StaticRegistra:public StaticRegistraBase \
{ \
StaticRegistra(const Key & theKey BOOST_PP_COMMA_IF(Nb) BOOST_PP_ENUM(Nb,PARAM,~)): \
theObjectPtr(new Derived(BOOST_PP_ENUM_PARAMS(Nb,P))) \
{ \
Singleton >::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
--------------------------------------------------------------------------------------------------------------
#ifndef PHACTORY_HEADER_GUARD
#define PHACTORY_HEADER_GUARD
#include<string>
#include<map>
#include<cassert>
#include
#include
#include
#include
#include
#include
#include
#include
#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::mapstd::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::mapstd::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(0));
return theIterator->second->RetrieveObject(id,theMap);
}
private:
typedef typename std::map InnerMap;
typedef typename std::map::const_iterator InnerMapIterator;
std::map theInnerMap;
};
#define PARAM(z,Nb,data) boost::get::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::mapstd::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::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 *>(0)
#undef MAX_PHACTORIES
#undef PARAM
#undef INNER_RETRIVE_OBJECT
#endif
-----------------------------------------------------------------------------------------------------------------------------------
#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 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 theRegistra(std::string("MyClassDouble"));
Registra theRegistraD(std::string("MyClassDoubleDerived"));
}
struct MyClassMultiple {
typedef boost::mpl::list Constructor_TypeList;
MyClassMultiple(std::string,std::vector<double>,double,MyClassDoubleDerived){}
virtual void f(){cout << " I am in MyClassMultiple \n";}
virtual ~MyClassMultiple(){};
};
namespace {
Registra theRegistraM(std::string("MyClassMultiple"));
StaticRegistra theStaticRegistraM(std::string("MyClassMultiple"),std::string("String"),std::vector<double>(2),1.0,MyClassDoubleDerived(1.0));
}
struct Dummy{};
struct Base {
typedef boost::mpl::list variant_type_list;
Base(){}
virtual void f()const=0;
virtual ~Base(){};
};
struct Derived :public Base {
typedef boost::mpl::list 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 thePhRegistra(std::string("DerivedObject"),PARAM_NAMES(theVarNames));
}
int main() {
char ch;
boost::shared_ptr<MyClassVoid> thePtrVoid(Singleton::instance().RetrieveObject("MyClassVoidDerived"));
thePtrVoid->f();
boost::shared_ptr<MyClassDouble> thePtrDoubleDerived(Singleton::instance().RetrieveObject("MyClassDoubleDerived",1.0));
thePtrDoubleDerived->f();
boost::shared_ptr<MyClassDouble> thePtrDouble(Singleton::instance().RetrieveObject("MyClassDouble",1.0));
thePtrDouble->f();
boost::shared_ptr<MyClassMultiple>
thePtrM(Singleton::instance().RetrieveObject("MyClassMultiple",std::string("String"),std::vector<double>(2),1.0,MyClassDoubleDerived(1.0)));
thePtrM->f();
boost::shared_ptr<MyClassMultiple>
thePtrSM(Singleton::instance().RetrieveObject("MyClassMultiple"));
thePtrSM->f();
std::map theMap;
theMap["Double"]=1.0;
theMap["Int"]=1;
theMap["String"]="hello";
theMap["Vector"]=std::vector<double>(10);
boost::shared_ptr<Base>
thePtrPhM(Singleton::instance().RetrieveObject("DerivedObject",theMap));
thePtrPhM->f();
cin >>ch;
}
--------------------------------------------------------------------------------------------------------------------------------------
----- Original Message ----
From: David Abrahams
To: boost-users@lists.boost.org
Sent: Thursday, 2 November, 2006 5:33:36 PM
Subject: Re: [Boost-users] Boost ROCKS !!!!!
Nindi Singh 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@lists.boost.org
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