Boost logo

Boost Users :

Subject: Re: [Boost-users] how to make a vector to derivedClass::create() methods
From: Victor Whiskey Yankee (victor.whiskey.yankee_at_[hidden])
Date: 2009-02-10 22:30:04


All,

Again thank you Steven for your great suggestion, though I have compiler
problems, using 1.38, 1.37, and even 1.33.1.
I am putting my code here so maybe I am missing something simple.

Thank you,
Victor

=====code starts here=======
// for thread-safe singleton
#include <boost/utility.hpp>
#include <boost/thread/once.hpp>
#include <boost/scoped_ptr.hpp>

// for the factory
#include <string>
#include <map>
#include <boost/shared_ptr.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/function.hpp>
#include <boost/lambda/lambda.hpp>
#include <boost/lambda/bind.hpp>
#include <boost/lambda/construct.hpp>

// for the main test
#include <assert.h>
#include <iostream>
#include <vector>

////////////////////////////////////////////////////////////////////////////////
// thread-safe singleton from http://www.boostcookbook.com/Recipe:/1235044
////////////////////////////////////////////////////////////////////////////////
template<class T>
class Singleton : private boost::noncopyable
   {
   public:
      static T& instance()
         {
         boost::call_once(init, flag);
         return *t;
         }

      static void init()
         {
         t.reset(new T());
         }

   protected:
      ~Singleton() {}
      Singleton() {}

   private:
      static boost::scoped_ptr<T> t;
      static boost::once_flag flag;
   };

template<class T> boost::scoped_ptr<T> Singleton<T>::t(0);
template<class T> boost::once_flag Singleton<T>::flag = BOOST_ONCE_INIT;

////////////////////////////////////////////////////////////////////////////////
// generic factory
////////////////////////////////////////////////////////////////////////////////

template<typename BaseType,typename KeyType>
class GenericFactory: public Singleton<GenericFactory<BaseType,KeyType> >
   {
   friend class Singleton<GenericFactory<BaseType,KeyType> >;
   typedef std::map<KeyType, boost::function<BaseType*()> > TypeMap_t;

   public:
         GenericFactory()
            { }

         ~GenericFactory()
            {}

         boost::shared_ptr<BaseType> create(const KeyType& typeName)
            {
            boost::mutex::scoped_lock lock(m_mutex);
            boost::shared_ptr<BaseType> answer;
            if ( m_creators.end() != m_creators.find(typeName) )
               {
               answer.reset( m_creators[typeName]() );
               }
            return answer;
            }

         template<typename DerivedType>
         inline void registrator(const KeyType& _key)
            {
            boost::mutex::scoped_lock lock(m_mutex);
            typename TypeMap_t::const_iterator i = m_creators.find(_key);
            if ( m_creators.end() == i )
               {
               m_creators[ _key ] = boost::lambda::new_ptr<DerivedType>();
               }
            }

   protected:
         TypeMap_t m_creators;
         mutable boost::mutex m_mutex;
   };

template <typename BaseType, typename KeyType, typename DerivedType>
struct RegisterDerived
   {
   RegisterDerived(const KeyType& _key)
         {
        
GenericFactory<BaseType,KeyType>::instance().registrator<DerivedType>(_key);
         }
   };

////////////////////////////////////////////////////////////////////////////////
// a simple base class
////////////////////////////////////////////////////////////////////////////////
class Base
   {
   public:
         Base()
            { }
         virtual ~Base()
            { }
         Base(const Base& rhs)
            { }
         Base& operator=(const Base& rhs)
            {
            if (&rhs != this)
               { ; }
            return *this;
            }
         virtual const std::string typeName() const=0;
   };

////////////////////////////////////////////////////////////////////////////////
// a Factory for our classes derived from Base
////////////////////////////////////////////////////////////////////////////////
typedef GenericFactory<Base,std::string> FooFactory;

////////////////////////////////////////////////////////////////////////////////
// derived class A
////////////////////////////////////////////////////////////////////////////////
class A: public Base
   {
   public:
         A()
            : Base()
            { }
         A(const A& rhs)
            : Base(rhs)
            { }
         A& operator=(const A& rhs)
            {
            if (&rhs != this)
               {
               (Base&)*this = rhs;
               }
            return *this;
            }
         virtual ~A()
            { }
         virtual const std::string typeName() const
            { return "a"; }
   };
// attempt to register the derived classes with the factory
RegisterDerived<Base,std::string,A> myARegistrar(std::string("a"));

////////////////////////////////////////////////////////////////////////////////
// derived class B
////////////////////////////////////////////////////////////////////////////////
class B: public Base
   {
   public:
         B()
            : Base()
            { }
         B(const B& rhs)
            : Base(rhs)
            { }
         B& operator=(const B& rhs)
            {
            if (&rhs != this)
               {
               (Base&)*this = rhs;
               }
            return *this;
            }
         virtual ~B()
            { }
         virtual const std::string typeName() const
            { return "b"; }
   };
// attempt to register the derived classes with the factory
RegisterDerived<Base,std::string,B> myBRegistrar(std::string("b"));

////////////////////////////////////////////////////////////////////////////////
// a simple test
////////////////////////////////////////////////////////////////////////////////
int main()
   {
   typedef boost::shared_ptr<Base> BasePtr;
   typedef std::vector< BasePtr > BaseList;

    {
    // try to create a classifier using an unregistered (i.e. unknown)
typeName
    BasePtr myPtr = FooFactory::instance().create("Z");
    assert ( NULL == myPtr );
    }

    {
    // try to create a derived class using its valid registered typeName
    BasePtr myPtr = FooFactory::instance().create("a");
    assert ( NULL != myPtr);
    assert ( myPtr->typeName() == "a" );
    }

    {
    // try to create a different derived class using a valid registered
typeName
    BasePtr myPtr = FooFactory::instance().create("b");
    assert ( NULL != myPtr);
    assert ( myPtr->typeName() == "b" );
    }

    BaseList myList;
    myList.push_back( FooFactory::instance().create("a") );
    myList.push_back( FooFactory::instance().create("b") );

   for ( BaseList::iterator i= myList.begin(); i != myList.end(); ++i)
      {
      std::cerr<<"The typename is "<<(*i)->typeName()<<std::endl;
      }

   return 0;
   }

=====code ends here=======


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