Re: [Boost-users] how to make a vector to derivedClass::create() methods

Victor.Whiskey.Yankee wrote:
Thank you for your patience. I am really wanting to make a factory that holds a std::map where the pair.first is a std::string and the pair.second is somehow a pointer to a constructor or create() method to any of several derived classes>.
I thought expressing in terms of vector might be simplified and enough for my understanding.
I see. How about using Boost.Function like this:
std::map<std::string, boost::function<Base*()> > factory_impl;
//...
factory_impl["Derived1"] = boost::lambda::new_ptr<Derived1>();
// ...
Base* b = factory_impl["Derived1"]()
Thank you Steve for your solution, it is working fine. I have a nice thread-safe singleton factory now, and it is generic using templates. I am now trying to make my derived classes register with the factory automatically, but cannot figure it out. I basically have this: template<typename BaseType, typename keyType> class GenericFactory { public: GenericFactory(); boost::shared_ptr<BaseType> create(const keyType& typeName); template<typeName DerivedType> void registrate(const keyType& _key); }; As said, I can register my derived classes with the above just fnie. I have tried writing a help class like I've seened "RegisterInFactory", but it escapes me. Thanks, Vic

AMDG Victor Whiskey Yankee wrote:
Thank you Steve for your solution, it is working fine. I have a nice thread-safe singleton factory now, and it is generic using templates.
I am now trying to make my derived classes register with the factory automatically, but cannot figure it out. I basically have this:
template<typename BaseType, typename keyType> class GenericFactory { public: GenericFactory();
boost::shared_ptr<BaseType> create(const keyType& typeName);
template<typeName DerivedType> void registrate(const keyType& _key); };
As said, I can register my derived classes with the above just fnie.
I have tried writing a help class like I've seened "RegisterInFactory", but it escapes me.
Your thinking of this? struct RegisterDerived { RegisterDerived() { factory.register<Derived>("Derived") } } registerDerived; In Christ, Steven Watanabe

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=======

AMDG Victor Whiskey Yankee wrote:
template <typename BaseType, typename KeyType, typename DerivedType> struct RegisterDerived { RegisterDerived(const KeyType& _key) {
GenericFactory<BaseType,KeyType>::instance().registrator<DerivedType>(_key)
This should be ...::instance().template registrator<DerivedType>(_key) In Christ, Steven Watanabe

Steven Watanabe wrote:
AMDG
Victor Whiskey Yankee wrote:
template <typename BaseType, typename KeyType, typename DerivedType> struct RegisterDerived { RegisterDerived(const KeyType& _key) {
GenericFactory<BaseType,KeyType>::instance().registrator<DerivedType>(_key)
This should be ...::instance().template registrator<DerivedType>(_key)
Is compiles now. Thanks! I guess the "thread safe singleton" recipe is having difficulty. It fails a boost assertion in method static T& instance() trying to return *t when ask for an instance of "z" in the test main. Interesting finding. If I move the myARestistrar and myBRegistrar to be inside main, then everything works. But must auto-register. -Vic
participants (2)
-
Steven Watanabe
-
Victor Whiskey Yankee