|
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