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

Duc*_*een 3 c++ boost

我有一个我想要存放在布料中的类树.我看到如何使用空的或预定义的构造函数实现元素的结构,但是我没有看到如何使用预定义的构造函数参数签名来解决这个问题.所以说我们以不影响工厂类的方式将不同的类型注册到工厂.我们的工厂看起来像这样:

Factory.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;
    }
};
Run Code Online (Sandbox Code Playgroud)

所以问题是:如何将typedef改为a typedef BaseType * (*base_creator_fn)(...);而不是current (),其次是如何转发参数instantiate,(BaseTypeCode const & name, ...)以及最后如何从构造函数中获取新的base_creator_fn,这些构造函数采用const ammount参数?

所以我希望在最后获得这样的用法示例:

Example.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;
};
Run Code Online (Sandbox Code Playgroud)

Example.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));
Run Code Online (Sandbox Code Playgroud)

Main.cpp的

#include "Example.hpp"

int main() {
    ExampleBase * p = Base::instantiate(ExampleTypeCode_Simple, 1);
}
Run Code Online (Sandbox Code Playgroud)

我的主要编译目标是最新的GCC和令人遗憾的Visual Studio 2012以及最新的服务包 - 所以C++ 11子集非常有限但尚未呈现.

Naw*_*waz 7

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);
    }
};
Run Code Online (Sandbox Code Playgroud)

这里是测试代码:我已经定义了两个派生类,其中一个在创建时接受两个参数,另一个不接受任何参数.

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;
}
Run Code Online (Sandbox Code Playgroud)

输出(在线演示):

DerivedExample
AnotherExample. a = 10, b = Mahfuza
Run Code Online (Sandbox Code Playgroud)

希望有所帮助.:-)