boost :: function имеет довольно гибкий фабричный шаблон: http://www.boost.org/doc/libs/1_54_0/libs/functional/factory/doc/html/index.html
Однако я предпочитаю создавать классы-оболочки, которые скрывают механизм сопоставления и создания объектов. Типичный сценарий, с которым я сталкиваюсь, - это необходимость сопоставить различные производные классы некоторого базового класса с ключами, где все производные классы имеют доступную общую сигнатуру конструктора. Вот решение, которое я придумал.
#ifndef GENERIC_FACTORY_HPP_INCLUDED
#ifndef BOOST_PP_IS_ITERATING
#include <unordered_map>
#include <functional>
#include <boost/preprocessor/iteration/iterate.hpp>
#include <boost/preprocessor/repetition.hpp>
#ifndef GENERIC_FACTORY_MAX_ARITY
#define GENERIC_FACTORY_MAX_ARITY 10
#endif
#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()
#define GENERIC_FACTORY_APPEND_PLACEHOLDER(z, current, last) BOOST_PP_COMMA() BOOST_PP_CAT(std::placeholders::_, BOOST_PP_ADD(current, 1))
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)() {}
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));
}
bool Deregister(const KeyType& key)
{
return (m_creatorMap.erase(key) == 1);
}
bool IsCreatable(const KeyType& key) const
{
return (m_creatorMap.count(key) != 0);
}
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:
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
#endif
Я вообще против интенсивного использования макросов, но здесь я сделал исключение. Приведенный выше код генерирует GENERIC_FACTORY_MAX_ARITY + 1 версии класса с именем GenericFactory_N для каждого N от 0 до GENERIC_FACTORY_MAX_ARITY включительно.
Использовать сгенерированные шаблоны классов просто. Предположим, вы хотите, чтобы фабрика создавала объекты, производные от BaseClass, с помощью сопоставления строк. Каждый из производных объектов принимает 3 целых числа в качестве параметров конструктора.
#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);
Деструктор класса GenericFactory_N является виртуальным, чтобы обеспечить следующее.
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;
Обратите внимание, что эта строка макроса универсального генератора фабрики
#define BOOST_PP_FILENAME_1 "GenericFactory.hpp"
Предполагается, что общий заголовочный файл фабрики называется GenericFactory.hpp.