如何将参数传递给工厂元素构造函数

How to pass arguments to factory elements constructors?

本文关键字:工厂 元素 构造函数 参数传递      更新时间:2023-10-16

我有一个要存储在结构中的类树。我看到了如何为具有空构造函数或预定义构造函数的元素实现结构,但我看不到如何使用未预定义的构造函数参数签名。假设我们以一种不直接影响工厂类的方式将不同的类型注册到工厂中。我们的工厂看起来是这样的:

工厂.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);