Templates & abstraction question

Discussion in 'C++' started by AzizMandar, Nov 9, 2006.

  1. AzizMandar

    AzizMandar Guest

    There is probably a better way to do this and if so I'm just as happy
    to see that way.


    I have a program where I have factories that each create various
    objects abstracted from a base class. The Factories all have a base
    class as well for the objects to point back to.

    So I have

    class CBFactory{
    public:
    CBFactory();
    ~CBFactory();
    }

    class CBObject{
    CBFactory* m_home;
    public:
    CBObject();
    ~CBObject();
    }

    class SillyObject:public CBObject{
    //Code that makes it unique
    public:
    SillyObject(CBFactory*); //Set the m_home on creation
    ~SillyObject();

    }

    class SillyFactory:public CBFactory,public singleton{
    public:
    SillyFactory();
    ~SillyFactory();
    CBObject* MakeObj(){
    SillyObject* NewObj = new SillyObject(this);
    return NewObj;
    }
    }


    Now Singleton just adds my singleton elements (It works a little
    diffrant but I included it to show the multiple inheritance I use)

    Right now I have a lot of member functions like MakeObj() and they are
    so similar in each factory that it would be nice to template them. The
    problem is I don't know if there is a way to let the template know that
    the dependant class type (SillyObject in this case) is derived from
    CBObjects since that is what I am returning a pointer to. I could
    probably explicit cast it and tell the compiler to ignore the casting
    but I figure there could be a more type safe way to do it.
     
    AzizMandar, Nov 9, 2006
    #1
    1. Advertising

  2. AzizMandar

    Guest

    AzizMandar wrote:
    > There is probably a better way to do this and if so I'm just as happy
    > to see that way.
    >
    >
    > I have a program where I have factories that each create various
    > objects abstracted from a base class. The Factories all have a base
    > class as well for the objects to point back to.
    >
    > So I have
    >
    > class CBFactory{
    > public:
    > CBFactory();
    > ~CBFactory();
    > }
    >
    > class CBObject{
    > CBFactory* m_home;
    > public:
    > CBObject();
    > ~CBObject();
    > }
    >
    > class SillyObject:public CBObject{
    > //Code that makes it unique
    > public:
    > SillyObject(CBFactory*); //Set the m_home on creation
    > ~SillyObject();
    >
    > }
    >
    > class SillyFactory:public CBFactory,public singleton{
    > public:
    > SillyFactory();
    > ~SillyFactory();
    > CBObject* MakeObj(){
    > SillyObject* NewObj = new SillyObject(this);
    > return NewObj;
    > }
    > }
    >
    >
    > Now Singleton just adds my singleton elements (It works a little
    > diffrant but I included it to show the multiple inheritance I use)
    >
    > Right now I have a lot of member functions like MakeObj() and they are
    > so similar in each factory that it would be nice to template them. The
    > problem is I don't know if there is a way to let the template know that
    > the dependant class type (SillyObject in this case) is derived from
    > CBObjects since that is what I am returning a pointer to. I could
    > probably explicit cast it and tell the compiler to ignore the casting
    > but I figure there could be a more type safe way to do it.


    so what's the problem in doing the following ?

    template<typename T>
    T* SillyFactory::MakeObj(){
    T* NewObj = new T(this);
    return NewObj;
    }

    Make the MakeObj function to be a static function and then you can use.

    SillyObject* p = SillyFactory::Create<SillyObject>();
     
    , Nov 9, 2006
    #2
    1. Advertising

  3. AzizMandar

    mlimber Guest

    AzizMandar wrote:
    > There is probably a better way to do this and if so I'm just as happy
    > to see that way.
    >
    >
    > I have a program where I have factories that each create various
    > objects abstracted from a base class. The Factories all have a base
    > class as well for the objects to point back to.
    >
    > So I have
    >
    > class CBFactory{
    > public:
    > CBFactory();
    > ~CBFactory();
    > }
    >
    > class CBObject{
    > CBFactory* m_home;
    > public:
    > CBObject();
    > ~CBObject();
    > }
    >
    > class SillyObject:public CBObject{
    > //Code that makes it unique
    > public:
    > SillyObject(CBFactory*); //Set the m_home on creation
    > ~SillyObject();
    >
    > }
    >
    > class SillyFactory:public CBFactory,public singleton{
    > public:
    > SillyFactory();
    > ~SillyFactory();
    > CBObject* MakeObj(){
    > SillyObject* NewObj = new SillyObject(this);
    > return NewObj;
    > }
    > }
    >
    >
    > Now Singleton just adds my singleton elements (It works a little
    > diffrant but I included it to show the multiple inheritance I use)
    >
    > Right now I have a lot of member functions like MakeObj() and they are
    > so similar in each factory that it would be nice to template them. The
    > problem is I don't know if there is a way to let the template know that
    > the dependant class type (SillyObject in this case) is derived from
    > CBObjects since that is what I am returning a pointer to. I could
    > probably explicit cast it and tell the compiler to ignore the casting
    > but I figure there could be a more type safe way to do it.


    Check out the factory and singleton classes described in _Modern C++
    Design_ by Alexandrescu. The code can be downloaded for free from:

    http://sourceforge.net/projects/loki-lib/

    You can see an example of the Singleton usage here:

    http://groups.google.com/group/comp.lang.c /msg/3eadedc5b34ee23d

    The factory allows you to register a creation function and then create
    using some ID. It's quite clever and quite useful!

    Cheers! --M
     
    mlimber, Nov 9, 2006
    #3
  4. AzizMandar

    AzizMandar Guest

    >so what's the problem in doing the following ?
    >
    > template<typename T>
    > T* SillyFactory::MakeObj(){
    > T* NewObj = new T(this);
    > return NewObj;
    >
    > }Make the MakeObj function to be a static function and then you can use.
    >
    > SillyObject* p = SillyFactory::Create<SillyObject>();


    The MakeObj() is no longer returning type CBObject* it is now
    returning the type T* (so SillyObject if I did
    SillyFactory<SillyObject>)

    When I would go to call CBOFactory::NewObj() from SillyFactory the
    return type would not match. I don't even think it would compile
    because the arguments match and return types don't.

    In my code I don't know that SIllyFactory or SillyObject will be used
    (I want to make what ever ones I need without changing the core
    program) So I can only deal with CBObject and CBOFactory. I can just
    explicitly override the function MakeObj() and make it virtual in
    CBOFactory but I am copying and pasting code every time and only
    changing the inherited CBObject class. I was hoping for a template
    solution but the reliance on the type T to be inherited from CBObject
    is causing a bit of a problem. Of course I guess I can explicit cast T
    to CBObject for the return type but if it was ever of a class not
    inherited from CBObject that would be REALLY bad (hence why that
    process would be 'EVIL')
     
    AzizMandar, Nov 9, 2006
    #4
  5. AzizMandar

    AzizMandar Guest

    > Check out the factory and singleton classes described in _Modern C++
    > Design_ by Alexandrescu. The code can be downloaded for free from:
    >
    > http://sourceforge.net/projects/loki-lib/
    >
    > You can see an example of the Singleton usage here:
    >
    > http://groups.google.com/group/comp.lang.c /msg/3eadedc5b34ee23d
    >
    > The factory allows you to register a creation function and then create
    > using some ID. It's quite clever and quite useful!
    >
    > Cheers! --M


    Thanks. I'll look into that. The Singleton is very similar to one I
    use so I'm happy to see I'm at least doing that right. I have read
    things similar to what you describe about the factory and was trying to
    avoid that in my program design (ID and lookup) but it is safe and it
    can be templated much easier. I'm just worried about performance of an
    ID lookup routine rather than a straight pointer call. I'm not worried
    about losing pointer or trying to call a deleted pointer (My garbage
    class is working well for that) but I will look over the information
    and maybe redesign some of my code.

    Thanks again
     
    AzizMandar, Nov 9, 2006
    #5
  6. AzizMandar

    Salt_Peter Guest

    AzizMandar wrote:
    > There is probably a better way to do this and if so I'm just as happy
    > to see that way.
    >
    >
    > I have a program where I have factories that each create various
    > objects abstracted from a base class. The Factories all have a base
    > class as well for the objects to point back to.
    >
    > So I have
    >
    > class CBFactory{
    > public:
    > CBFactory();
    > ~CBFactory();
    > }
    >
    > class CBObject{
    > CBFactory* m_home;
    > public:
    > CBObject();
    > ~CBObject();
    > }
    >
    > class SillyObject:public CBObject{
    > //Code that makes it unique
    > public:
    > SillyObject(CBFactory*); //Set the m_home on creation
    > ~SillyObject();
    >
    > }
    >
    > class SillyFactory:public CBFactory,public singleton{
    > public:
    > SillyFactory();
    > ~SillyFactory();
    > CBObject* MakeObj(){
    > SillyObject* NewObj = new SillyObject(this);
    > return NewObj;
    > }
    > }
    >


    Your class definitions need semicolons. MakeObj() should be static. Any
    base class you allocate via new/delete needs a vitual d~tor (MakeObj()
    is returning a base ptr). The goal is to isolate the singleton's
    interface so only the static creator function is accessible. You should
    prefer smart pointers over new/delete.

    >
    > Now Singleton just adds my singleton elements (It works a little
    > diffrant but I included it to show the multiple inheritance I use)
    >
    > Right now I have a lot of member functions like MakeObj() and they are
    > so similar in each factory that it would be nice to template them. The
    > problem is I don't know if there is a way to let the template know that
    > the dependant class type (SillyObject in this case) is derived from
    > CBObjects since that is what I am returning a pointer to. I could
    > probably explicit cast it and tell the compiler to ignore the casting
    > but I figure there could be a more type safe way to do it.
     
    Salt_Peter, Nov 9, 2006
    #6
  7. AzizMandar

    Guest

    You are more than welcome to look at my factory code, it makes heavy
    use of Boost ( which is a good thing). There are actualy 3 factories.
    One returning new objects derived from a base class, and the base class
    must have a typelist to identify the constructor to be used by the
    factory.
    The second returns a reference to a shared, static object, again the
    base class must have a typelist identifying the signature of the
    constructor.

    The third Factory produces derived objects of a given base class, but
    queries the derived objects for a typelist so it can work out which
    consructor to call to produce the object.

    I'll first pate in the main.cpp, it shoes example code using the
    factory, followed by the factory code.


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

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


    }
    -------------------------------------------------------------------------------------------------------------------------------------
    The Factory code

    ---------------------------------------------------------------------------
    <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=std::string(theVariableNames);
    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)!=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
    -------------------------------------------------------------------------------------------------------------------------------
     
    , Nov 10, 2006
    #7
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Alex
    Replies:
    2
    Views:
    549
  2. Fred
    Replies:
    1
    Views:
    605
    Neredbojias
    Sep 26, 2005
  3. JKop
    Replies:
    3
    Views:
    480
  4. craig
    Replies:
    1
    Views:
    409
    Phlip
    Mar 22, 2006
  5. recover
    Replies:
    2
    Views:
    814
    recover
    Jul 25, 2006
Loading...

Share This Page