【问题标题】:Variadic templates Factory using std::bind and std::placeholders使用 std::bind 和 std::placeholders 的可变参数模板工厂
【发布时间】:2018-11-26 02:08:44
【问题描述】:

我正在尝试实现可以​​将插件实例化为插件实例的工厂模式。 目标是拥有一个由插件类型模板化的工厂类,以及插件创建函数的参数,例如:

APluginInstance 和 A2PluginInstance 都派生 ABase。 它们在工厂中应该每个都有不同的插件,但在工厂中映射到一个名称。

class ABase {};

class APluginInstance : public ABase {

public:

    static std::shared_ptr<ABase> create(double a, double b)
    {
        return std::shared_ptr<ABase>(new APluginInstance(a,b));
    }

    APluginInstance(double a, double b)
    : ret(a + b)
    {
        std::cout << ret << std::endl;
    }

    double ret;
};


class A2PluginInstance : public ABase {

public:

    static std::shared_ptr<ABase> create(double a, double b)
    {
        return std::shared_ptr<ABase>(new APluginInstance(a,b));
    }

    A2PluginInstance(double a, double b)
    : ret(a - b)
    {
        std::cout << ret << std::endl;
    }

    double ret;
};

同样,我们在其他地方还有另一种类型的插件:

class BBase {};

class BPluginInstance : public BBase {

public:

    static std::shared_ptr<BBase> create(int a)
    {
        return std::shared_ptr<BBase>(new BPluginInstance(a));
    }

    BPluginInstance(int a)
    {
        std::cout  << a << std::endl;
    }
};

class B2PluginInstance : public BBase {

public:

    static std::shared_ptr<BBase> create(int a)
    {
        return std::shared_ptr<BBase>(new B2PluginInstance(a));
    }

    B2PluginInstance(int a)
    {
        std::cout  << -a << std::endl;
    }
};

现在这里是接受模板参数的通用插件类 基本实例类型(从 create 函数返回的类型)和该函数的参数:

template <typename PluginInstanceBaseType, typename ...Args>
class Plugin
{
public:

    using PluginInstanceBase_t = PluginInstanceBaseType;


    void setFunc(const std::function<PluginInstanceBaseType(Args...)>& func)
    {
        _createFunc = func;
    }

    PluginInstanceBaseType create(const Args&... args)
    {
        return _createFunc(args...);
    }

    std::function<PluginInstanceBaseType(Args...)> _createFunc;

};

所以我们有 2 种插件类型:

using APlugin = Plugin<std::shared_ptr<ABase>, double, double>;
using BPlugin = Plugin<std::shared_ptr<BBase>, int>;

现在这里是工厂类,它采用参数中的插件类型(APlugin 或 BPlugin)

template <typename PluginType>
class Factory
{

public:

    using PluginInstanceBase_t = typename PluginType::PluginInstanceBase_t;


    template <typename T, typename...Args>
    void addPlugin(const std::string& name, const std::function<T(Args...)>& f)
    {
        std::shared_ptr<PluginType> plugin(new PluginType());
        plugin->setFunc(f);
        _plugins[name] = plugin;
    }

    template <typename... Args>
    PluginInstanceBase_t create(const std::string& name, const Args&... args)
    {
        auto found = _plugins.find(name);
        if (found == _plugins.end()) {
            return PluginInstanceBase_t();
        }
        return found->second->create(args...);
    }

private:


    std::map<std::string, std::shared_ptr<PluginType> > _plugins;
};

我们的 2 家工厂:

using AFactory = Factory<APlugin>;
using BFactory = Factory<BPlugin>;

最后,这里是一个示例用法:

int main()
{

     {
        // Works
        APlugin tmpa;
        tmpa.setFunc(APluginInstance::create);
    }

    AFactory af;
    BFactory bf;

    // Doesn't work
    //af.addPlugin("A1", APluginInstance::create);
    //af.addPlugin("A2", A2PluginInstance::create);
    //bf.addPlugin("B1", BPluginInstance::create);
    //bf.addPlugin("B2", B2PluginInstance::create);

    std::shared_ptr<ABase> a = af.create("A1",2., 4.);
    std::shared_ptr<ABase> a2 = af.create("A2",2., 4.);
    std::shared_ptr<BBase> b = bf.create("B1", 1);
    std::shared_ptr<BBase> b2 = bf.create("B2", 1);

    return 0;
}

直接创建插件并使用实例创建函数调用 setFunc。 但是,当使用工厂的函数 addPlugin 时,它不起作用,因为它无法将 create 函数与 std::function 类型匹配。

我正在尝试为它找到一个修复程序,以便我可以使用 addPlugin 函数

以下是 Coliru 上的一个链接,其中包含一个实时示例:

http://coliru.stacked-crooked.com/a/cba8fe84b4d6bd85

【问题讨论】:

    标签: c++ c++11 variadic-templates factory std-function


    【解决方案1】:

    您的问题是您传递的是函数指针,而不是 std::function 到 addPlugin。

    您要求将指针T(*)(Args...) 隐式转换为std::function&lt;T,Args...&gt;,然后扣除T,Args...。但是模板参数推导不考虑隐式转换。

    您要么需要将std::function 传递给addPlugin,因此可以推断出T,Args...,或者您需要另一个接受函数指针的addPlugin 重载,然后调用@ 的std::function 重载987654329@。有点像..

    ...
    
    template <typename T, typename...Args>
    void addPlugin(const std::string& name, T(*func)(Args...) )
    {
        addPlugin(name,std::function<T(Args...)>(func));
    }
    
    template <typename T, typename...Args>
    void addPlugin(const std::string& name, const std::function<T(Args...)>& f)
    {
        std::shared_ptr<PluginType> plugin(new PluginType());
        plugin->setFunc(f);
        _plugins[name] = plugin;
    }
    
    ...
    

    Demo

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-04-30
      • 2019-01-18
      • 1970-01-01
      • 2016-06-11
      • 1970-01-01
      • 2023-04-07
      • 2020-02-15
      相关资源
      最近更新 更多