boost::functional has a factory template which is quite flexible: http://www.boost.org/doc/libs/1_54_0/libs/functional/factory/doc/html/index.html
My preference though is to generate wrapper classes which hide the mapping and object creation mechanism. The common scenario I encounter is the need to map different derived classes of some base class to keys, where the derived classes all have a common constructor signature available. Here is the solution I've come up with so far.
#ifndef GENERIC_FACTORY_HPP_INCLUDED //BOOST_PP_IS_ITERATING is defined when we are iterating over this header file. #ifndef BOOST_PP_IS_ITERATING //Included headers. #include <unordered_map> #include <functional> #include <boost/preprocessor/iteration/iterate.hpp> #include <boost/preprocessor/repetition.hpp> //The GENERIC_FACTORY_MAX_ARITY directive controls the number of factory classes which will be generated. #ifndef GENERIC_FACTORY_MAX_ARITY #define GENERIC_FACTORY_MAX_ARITY 10 #endif //This macro magic generates GENERIC_FACTORY_MAX_ARITY + 1 versions of the GenericFactory class. //Each class generated will have a suffix of the number of parameters taken by the derived type constructors. #define BOOST_PP_FILENAME_1 "GenericFactory.hpp" #define BOOST_PP_ITERATION_LIMITS (0,GENERIC_FACTORY_MAX_ARITY) #include BOOST_PP_ITERATE() #define GENERIC_FACTORY_HPP_INCLUDED #else #define N BOOST_PP_ITERATION() //This is the Nth iteration of the header file. #define GENERIC_FACTORY_APPEND_PLACEHOLDER(z, current, last) BOOST_PP_COMMA() BOOST_PP_CAT(std::placeholders::_, BOOST_PP_ADD(current, 1)) //This is the class which we are generating multiple times template <class KeyType, class BasePointerType BOOST_PP_ENUM_TRAILING_PARAMS(N, typename T)> class BOOST_PP_CAT(GenericFactory_, N) { public: typedef BasePointerType result_type; public: virtual ~BOOST_PP_CAT(GenericFactory_, N)() {} //Registers a derived type against a particular key. template <class DerivedType> void Register(const KeyType& key) { m_creatorMap[key] = std::bind(&BOOST_PP_CAT(GenericFactory_, N)::CreateImpl<DerivedType>, this BOOST_PP_REPEAT(N, GENERIC_FACTORY_APPEND_PLACEHOLDER, N)); } //Deregisters an existing registration. bool Deregister(const KeyType& key) { return (m_creatorMap.erase(key) == 1); } //Returns true if the key is registered in this factory, false otherwise. bool IsCreatable(const KeyType& key) const { return (m_creatorMap.count(key) != 0); } //Creates the derived type associated with key. Throws std::out_of_range if key not found. BasePointerType Create(const KeyType& key BOOST_PP_ENUM_TRAILING_BINARY_PARAMS(N,const T,& a)) const { return m_creatorMap.at(key)(BOOST_PP_ENUM_PARAMS(N,a)); } private: //This method performs the creation of the derived type object on the heap. template <class DerivedType> BasePointerType CreateImpl(BOOST_PP_ENUM_BINARY_PARAMS(N,const T,& a)) { BasePointerType pNewObject(new DerivedType(BOOST_PP_ENUM_PARAMS(N,a))); return pNewObject; } private: typedef std::function<BasePointerType (BOOST_PP_ENUM_BINARY_PARAMS(N,const T,& BOOST_PP_INTERCEPT))> CreatorFuncType; typedef std::unordered_map<KeyType, CreatorFuncType> CreatorMapType; CreatorMapType m_creatorMap; }; #undef N #undef GENERIC_FACTORY_APPEND_PLACEHOLDER #endif // defined(BOOST_PP_IS_ITERATING) #endif // include guard
I am generally opposed to heavy macro use, but I've made an exception here. The above code generates GENERIC_FACTORY_MAX_ARITY + 1 versions of a class named GenericFactory_N, for each N between 0 and GENERIC_FACTORY_MAX_ARITY inclusive.
Using the generated class templates is easy. Suppose you want a factory to create BaseClass derived objects using a string mapping. Each of the derived objects take 3 integers as constructor parameters.
#include "GenericFactory.hpp" typedef GenericFactory_3<std::string, std::shared_ptr<BaseClass>, int, int int> factory_type; factory_type factory; factory.Register<DerivedClass1>("DerivedType1"); factory.Register<DerivedClass2>("DerivedType2"); factory.Register<DerivedClass3>("DerivedType3"); factory_type::result_type someNewObject1 = factory.Create("DerivedType2", 1, 2, 3); factory_type::result_type someNewObject2 = factory.Create("DerivedType1", 4, 5, 6);
The GenericFactory_N class destructor is virtual to allow the following.
class SomeBaseFactory : public GenericFactory_2<int, BaseType*, std::string, bool> { public: SomeBaseFactory() : GenericFactory_2() { Register<SomeDerived1>(1); Register<SomeDerived2>(2); } }; SomeBaseFactory factory; SomeBaseFactory::result_type someObject = factory.Create(1, "Hi", true); delete someObject;
Note that this line of the generic factory generator macro
#define BOOST_PP_FILENAME_1 "GenericFactory.hpp"
Assumes the generic factory header file is named GenericFactory.hpp