使用 std::bind 和 std::placeholders 的可变模板工厂
Variadic templates Factory using std::bind and std::placeholders
我正在尝试实现一个可以将插件实例化为插件实例的工厂模式。
目标是拥有一个工厂 class,由插件类型和插件创建函数的参数模板化,例如:
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;
}
};
现在这里是接受模板参数的通用插件 class
基本实例类型(从 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>;
现在这里是工厂 class,它将插件类型作为参数(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 时,它不起作用,因为它无法将创建函数与 std::function 类型匹配。
我正在尝试为它找到一个修复程序,以便我可以使用 addPlugin 函数
这是 Coliru 上的一个 link 实例:
你的问题是你传递的是函数指针,而不是 std::function 到 addPlugin。
您要求从指针 T(*)(Args...)
到 std::function<T,Args...>
的隐式转换,然后进行 T,Args...
的推导。但是模板参数推导不考虑隐式转换。
您要么需要将 std::function
传递给 addPlugin
,以便可以推导出 T,Args...
,要么您需要另一个接受函数指针的 addPlugin
重载,然后调用 addPlugin
的 std::function 重载。像..
...
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;
}
...
我正在尝试实现一个可以将插件实例化为插件实例的工厂模式。 目标是拥有一个工厂 class,由插件类型和插件创建函数的参数模板化,例如:
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;
}
};
现在这里是接受模板参数的通用插件 class 基本实例类型(从 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>;
现在这里是工厂 class,它将插件类型作为参数(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 时,它不起作用,因为它无法将创建函数与 std::function 类型匹配。
我正在尝试为它找到一个修复程序,以便我可以使用 addPlugin 函数
这是 Coliru 上的一个 link 实例:
你的问题是你传递的是函数指针,而不是 std::function 到 addPlugin。
您要求从指针 T(*)(Args...)
到 std::function<T,Args...>
的隐式转换,然后进行 T,Args...
的推导。但是模板参数推导不考虑隐式转换。
您要么需要将 std::function
传递给 addPlugin
,以便可以推导出 T,Args...
,要么您需要另一个接受函数指针的 addPlugin
重载,然后调用 addPlugin
的 std::function 重载。像..
...
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;
}
...