$include_dir="/home/hyper-archives/boost-users/include"; include("$include_dir/msg-header.inc") ?>
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://listarchives.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