如何将参数传递给工厂元素构造函数
How to pass arguments to factory elements constructors?
我有一个要存储在结构中的类树。我看到了如何为具有空构造函数或预定义构造函数的元素实现结构,但我看不到如何使用未预定义的构造函数参数签名。假设我们以一种不直接影响工厂类的方式将不同的类型注册到工厂中。我们的工厂看起来是这样的:
工厂.hpp:
#include <unordered_map>
#include <string>
template<class BaseType, class BaseTypeCode>
class Factory {
public:
typedef BaseType * (*base_creator_fn)();
typedef std::unordered_map<BaseTypeCode, base_creator_fn> registry_map;
static registry_map & registry() {
static registry_map impl;
return impl;
}
static BaseType * instantiate(BaseTypeCode const & name) {
auto it = registry().find(name);
return it == registry().end() ? nullptr : (it->second)();
}
virtual ~Factory() = default;
};
template<class BaseClass, class BaseTypeCode>
struct Registrar {
Registrar(BaseTypeCode name, Factory<BaseClass>::base_creator_fn func) {
Factory<BaseClass>::registry()[name] = func;
}
};
所以问题是:如何对typedef BaseType * (*base_creator_fn)(...);
而不是当前的()
进行typedef,其次是如何在instantiate
中转发将接收(BaseTypeCode const & name, ...)
的参数,最后是如何从接收大量参数的构造函数中获得新的base_creator_fn?
所以我希望最后能得到这样的用法示例:
示例.hpp:
#include "Factory.hpp"
enum ExampleTypeCode { ExampleTypeCode_Simple = 1 };
class ExampleBase {
virtual ~ExampleBase(){}
};
class Example : public ExampleBase {
Example(int i) {}
virtual ~Example(){}
static Registrar<ExampleBase, ExampleTypeCode> registrar;
};
示例.cpp:
#include <boost/bind.hpp>
#include <boost/lambda.hpp>
#include "Example.hpp"
Registrar<Example, ExampleTypeCode> Example::registrar(ExampleTypeCode_Simple, boost::bind(boost::lambda::new_ptr<Example>, _firstVarArg));
Main.cpp
#include "Example.hpp"
int main() {
ExampleBase * p = Base::instantiate(ExampleTypeCode_Simple, 1);
}
我的主要编译目标是最新的GCC和带有最新service pack的Visual Studio 2012,所以C++11子集还很有限。
Variadic模板可以在这里提供帮助。我使用void*
作为registry_map
的第二种类型,这样我们就可以在注册表中存储任何类型的函数。下面是一个演示基本思想的最小代码:
class Base
{
public:
typedef std::unordered_map<std::string, void*> registry_map;
virtual ~Base() = default;
static registry_map & registry()
{
static registry_map impl;
return impl;
}
template<typename ...T>
static Base * instantiate(std::string const & name, T&&...args)
{
auto it = registry().find(name);
if ( it == registry().end()) return 0;
typedef Base* (*create_type)(T...);
auto create_fun = reinterpret_cast<create_type>(it->second);
return create_fun(args...);
}
virtual void f() = 0;
};
struct Registrar
{
template<typename F>
Registrar(std::string name, F func)
{
Base::registry()[name] = reinterpret_cast<void*>(func);
}
};
测试代码如下:我定义了两个派生类,其中一个在创建时接受两个参数,另一个不接受任何参数。
class DerivedExample : public Base
{
static Registrar registrar;
public:
static Base * create() { return new DerivedExample; }
virtual void f() override { std::cout << "DerivedExample" << std::endl; }
};
Registrar DerivedExample::registrar("DerivedExample", DerivedExample::create);
class AnotherExample : public Base
{
static Registrar registrar;
int a;
const char *b;
public:
AnotherExample(int a, const char *b) : a(a), b(b) {}
static Base * create(int a, const char *b) { return new AnotherExample(a,b); }
virtual void f() override { std::cout << "AnotherExample. a = " << a << ", b = " << b << std::endl; }
};
Registrar AnotherExample::registrar("AnotherExample", AnotherExample::create);
int main()
{
Base * p = Base::instantiate("DerivedExample");
Base * q = Base::instantiate("AnotherExample", 10, "Mahfuza");
p->f();
q->f();
delete p;
delete q;
}
输出(在线演示):
DerivedExample
AnotherExample. a = 10, b = Mahfuza
希望能有所帮助。:-)
您可以将您的工厂与构建器结合起来,以获得您想要的行为。构建器将保存参数。
template<class BaseType, class BaseTypeCode, class BaseTypeBuilder>
class Factory {
public:
typedef BaseType * (*base_creator_fn)(BaseTypeBuilder const &);
//...
static BaseType * instantiate(BaseTypeCode const & name,
BaseTypeBuilder const & builder
= BaseTypeBuilder()) {
auto it = registry().find(name);
return it == registry().end() ? nullptr : (it->second)(builder);
}
virtual ~Factory() = default;
};
然后,为Example
创建一个生成器。构建器可以根据您的需要而复杂,以帮助区分需要调用的构造函数:
class ExampleBuilder {
boost::optional<int> i;
public:
ExampleBuilder () {}
void set_i (int x) { i = x; }
static Example * create (const ExampleBuilder &builder) {
if (builder.i) return new Example(builder.i);
else return new Example();
}
};
Registrar<Example, ExampleTypeCode, ExampleBuilder>
Example::registrar(ExampleTypeCode_Simple, ExampleBuilder::create);
ExampleBuilder build;
build.set_i(1);
ExampleBase * p = Base::instantiate(ExampleTypeCode_Simple, build);
相关文章:
- Mongodb c++驱动程序:如何查询元素的数组
- 将数组作为参数传递给函数安全吗?作为第三方职能部门,可以探索他们想要的之外的其他元素
- 使用strcpy将char数组的元素复制到另一个数组
- 使用不带参数的函数访问结构元素
- 给定n个元素的m个集合.在C++中找到出现在最大集合数中的元素
- C++如何通过用户输入删除列表元素
- lower_bound()返回最后一个元素
- 基于多个条件处理地图中的所有元素
- 调整大小后指向元素值的指针unordered_map有效?
- 使用std::transform将一个范围的元素添加到另一个范围中
- 使用函数"remove"删除重复元素
- 具有最大子序列大小的序列,每个元素都相同
- 如何将两个不同矢量的同一位置的两个元素组合在一起
- 如何将元素添加到数组的线程安全函数?
- 有没有办法将谓词中的元素偏移量传递给 std 算法?
- 我想访问std::unique_ptr中的一个特定元素
- 如何通过 getter 函数删除矢量的元素?
- 向量元素的引用地址与它所指向的向量元素的地址不同.为什么
- 如何为所有“ std :: array”的工厂结构进行部分专业化,该结构超过4`元素
- 如何将参数传递给工厂元素构造函数