【发布时间】:2015-03-19 10:04:28
【问题描述】:
我正在尝试编写一个工厂类,它的标准接口如下所示:
Register<MyBase, MyDerived> g_regDerived("myderived"); // register to factory
现在调用:
auto* d = Factory<MyBase>::instance().create("myderived", 1, 2, 3);
将调用构造函数MyDerived(1,2,3)并返回一个指向创建对象的指针
这听起来像是 C++11 应该可以实现的,但我不知道该怎么做。
从标准类型擦除工厂开始:
template<typename BaseT>
class Factory {
public:
static Factory* instance() {
static Factory inst;
return &inst;
}
template<typename T>
void reg(const string& name) {
m_stock[name].reset(new Creator<T>);
}
BaseT* create(const string& name) {
return m_stock[name]->create();
}
private:
struct ICreator {
virtual BaseT* create() = 0;
};
template<typename T>
struct Creator : public ICreator {
virtual BaseT* create() {
return new T;
}
};
std::map<string, std::unique_ptr<ICreator>> m_stock;
};
template<typename BaseT, typename T>
class Register {
public:
Register(const QString& name) {
Factory<BaseT>::instance()->reg<T>(name);
}
};
这里的问题是,一旦你删除了创建对象的类型,你就不能再传递任意模板转发参数,因为你需要通过虚函数传递它们。
这个问题的答案:
How to pass a function pointer that points to constructor?
谈论类似的事情,但答案是通过一个特定于每个派生类的函数。我想直接使用类构造函数,不用写create()函数。
【问题讨论】:
-
我认为做到这一点完美是不可能的;函数的参数实际上是compile-time,与其他一些语言相比,例如Java 或C#。 (他们可以通过反射动态调用函数)当然C++有compile-time反射,但是你想动态调用函数。我建议模仿这些运行时反射:你可以使用类似
void *create(const std::vector<std::pair<void *, std::type_info *>> &params);的东西。您还可以提供宏或模板来帮助客户制作这个“创建”功能。 -
如果你通过引入一个基本上是
boost::any列表的config类来允许某种动态初始化,我会容易得多,并且总是允许作为未来的单个参数- 创建类。 -
create()函数有什么问题? -
@Adrian 你可以假设我的问题有充分的理由。用我已经说清楚的无用答案向它发送垃圾邮件对我没有帮助是很粗鲁的。
-
我尝试并没有假设,但如果没有更多信息,您可能正在尝试做一些不必要和/或适得其反的事情。陈述你的理由可能会帮助人们想出你没有想到的解决方案,因为你离问题太近了。作为拥有 36k 代表的人,您应该知道这一点。至于你说我很粗鲁,因为你认为我在发送垃圾邮件是 粗鲁。如果您想要更好的答案,请提出一个对一般社区更有用的问题。
标签: templates c++11 factory type-erasure