C++:可以调用任何构造函数的通用工厂?
C++: Generic factory that can call any constructor?
我正在尝试编写一个工厂 class,它将具有如下所示的标准接口:
Register<MyBase, MyDerived> g_regDerived("myderived"); // register to factory
正在通话:
auto* d = Factory<MyBase>::instance().create("myderived", 1, 2, 3);
将调用构造函数 MyDerived(1,2,3)
和 return 指向已创建对象的指针
这听起来像是 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?
谈论类似的事情,但答案是通过一个特定于每个派生 class 的函数。我想直接使用 class 构造函数而不必编写 create()
函数。
我不知道您为什么不喜欢编写 create()
函数。所以这是我实现的一个。
#include <iostream>
#include <utility>
using namespace std;
class C
{
public:
virtual char const* whoAmI() const = 0;
};
class A : public C
{
public:
A(int a1)
{
cout << "A(" << a1 << ")" << endl;
}
A(float a1)
{
cout << "A(" << a1 << ")" << endl;
}
virtual char const* whoAmI() const override
{
return "A";
}
};
class B : public C
{
public:
B(int a1)
{
cout << "B(" << a1 << ")" << endl;
}
B(float a1)
{
cout << "B(" << a1 << ")" << endl;
}
virtual char const* whoAmI() const override
{
return "B";
}
};
template<typename BASET>
class Factory
{
public:
// could use a is_base type trait test here
template <typename T, typename...ARGs>
static BASET* create(ARGs&&...args)
{
return new T(forward<ARGs>(args)...);
}
};
int main()
{
Factory<C> factory;
C* a = factory.create<A>(1);
C* b = factory.create<B>(1.0f);
cout << a->whoAmI() << endl;
cout << b->whoAmI() << endl;
return 0;
}
注意:我并没有做你做的所有事情,我只是实现了创建功能。我将最终实施留给您。
这使用完美转发使 varidict 模板能够将任意数量的参数传递给构造函数。然后,您的注册函数可以为特定参数集存储特定模板实例的函数指针。
编辑
我忘记使用适当的forward<ARGs>(args)...
调用来实现完美转发。现已添加。
至于你认为这没有用,这里是你的工厂的完整实现,使用完美转发和可变参数模板,允许特定工厂实例的特定类型的特定数量的参数:
#include <string>
#include <map>
#include <memory>
#include <utility>
#include <iostream>
using namespace std;
template<typename BaseT, typename...ARGs>
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, ARGs&&...args) {
return m_stock[name]->create(forward<ARGs>(args)...);
}
private:
struct ICreator
{
virtual BaseT* create(ARGs&&...) = 0;
};
template<typename T>
struct Creator : public ICreator {
virtual BaseT* create(ARGs&&...args) override
{
return new T(forward<ARGs>(args)...);
}
};
std::map<string, std::unique_ptr<ICreator>> m_stock;
};
template<typename BaseT, typename T, typename...ARGs>
class Register {
public:
Register(const string& name) {
auto instance = Factory<BaseT, ARGs...>::instance();
instance->template reg<T>(name);
}
};
struct C
{
virtual char const * whoAmI() const = 0;
};
struct A : public C
{
A(int a1, int a2)
{
cout << "Creating A(" << a1 << ", " << a2 << ")" << endl;
}
virtual char const * whoAmI() const override
{
return "A";
}
};
struct B : public C
{
B(int b1, int b2)
{
cout << "Creating B(" << b1 << ", " << b2 << ")" << endl;
}
B(int b1, int b2, int b3)
{
cout << "Creating B(" << b1 << ", " << b2 << ", " << b3 << ")" << endl;
}
virtual char const * whoAmI() const override
{
return "B";
}
};
typedef int I;
Register<C, A, I, I> a("a");
Register<C, B, I, I> b("b");
Register<C, B, I, I, I> b3("b");
int main()
{
C* a = Factory<C, I, I>::instance()->create("a", 1, 2);
C* b = Factory<C, I, I>::instance()->create("b", 3, 4);
C* b3 = Factory<C, I, I, I>::instance()->create("b", 5, 6, 7);
cout << "I am a " << a->whoAmI() << endl;
cout << "I am a " << b->whoAmI() << endl;
cout << "I am a " << b3->whoAmI() << endl;
return 0;
}
这是你想要的吗?如果您不想处理函数参数,请使用辅助模板函数为您推断它们,如下所示:
template <typename BaseT, typename...ARGs>
BaseT* create(const string& name, ARGs&&...args)
{
return Factory<C, ARGs...>::instance()->create(name, forward<ARGs>(args)...);
}
int main()
{
C* a = create<C>("a", 1, 2);
C* b = create<C>("b", 3, 4);
C* b3 = create<C>("b", 3, 4, 5);
cout << "I am a " << a->whoAmI() << endl;
cout << "I am a " << b->whoAmI() << endl;
cout << "I am a " << b3->whoAmI() << endl;
return 0;
}
它的额外好处是允许通过明显的单个函数 API 提供多个构造函数签名(它看起来只是一个,但实际上是 N 其中 N 是您允许的不同签名的数量)。这都可以通过这个online demo.
查看
您仍然需要使用我之前描述的相同注册,可以通过宏缩短。
如果这仍然不是您想要的,请在您的问题中添加更多细节。
我正在尝试编写一个工厂 class,它将具有如下所示的标准接口:
Register<MyBase, MyDerived> g_regDerived("myderived"); // register to factory
正在通话:
auto* d = Factory<MyBase>::instance().create("myderived", 1, 2, 3);
将调用构造函数 MyDerived(1,2,3)
和 return 指向已创建对象的指针
这听起来像是 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?
谈论类似的事情,但答案是通过一个特定于每个派生 class 的函数。我想直接使用 class 构造函数而不必编写 create()
函数。
我不知道您为什么不喜欢编写 create()
函数。所以这是我实现的一个。
#include <iostream>
#include <utility>
using namespace std;
class C
{
public:
virtual char const* whoAmI() const = 0;
};
class A : public C
{
public:
A(int a1)
{
cout << "A(" << a1 << ")" << endl;
}
A(float a1)
{
cout << "A(" << a1 << ")" << endl;
}
virtual char const* whoAmI() const override
{
return "A";
}
};
class B : public C
{
public:
B(int a1)
{
cout << "B(" << a1 << ")" << endl;
}
B(float a1)
{
cout << "B(" << a1 << ")" << endl;
}
virtual char const* whoAmI() const override
{
return "B";
}
};
template<typename BASET>
class Factory
{
public:
// could use a is_base type trait test here
template <typename T, typename...ARGs>
static BASET* create(ARGs&&...args)
{
return new T(forward<ARGs>(args)...);
}
};
int main()
{
Factory<C> factory;
C* a = factory.create<A>(1);
C* b = factory.create<B>(1.0f);
cout << a->whoAmI() << endl;
cout << b->whoAmI() << endl;
return 0;
}
注意:我并没有做你做的所有事情,我只是实现了创建功能。我将最终实施留给您。
这使用完美转发使 varidict 模板能够将任意数量的参数传递给构造函数。然后,您的注册函数可以为特定参数集存储特定模板实例的函数指针。
编辑
我忘记使用适当的forward<ARGs>(args)...
调用来实现完美转发。现已添加。
至于你认为这没有用,这里是你的工厂的完整实现,使用完美转发和可变参数模板,允许特定工厂实例的特定类型的特定数量的参数:
#include <string>
#include <map>
#include <memory>
#include <utility>
#include <iostream>
using namespace std;
template<typename BaseT, typename...ARGs>
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, ARGs&&...args) {
return m_stock[name]->create(forward<ARGs>(args)...);
}
private:
struct ICreator
{
virtual BaseT* create(ARGs&&...) = 0;
};
template<typename T>
struct Creator : public ICreator {
virtual BaseT* create(ARGs&&...args) override
{
return new T(forward<ARGs>(args)...);
}
};
std::map<string, std::unique_ptr<ICreator>> m_stock;
};
template<typename BaseT, typename T, typename...ARGs>
class Register {
public:
Register(const string& name) {
auto instance = Factory<BaseT, ARGs...>::instance();
instance->template reg<T>(name);
}
};
struct C
{
virtual char const * whoAmI() const = 0;
};
struct A : public C
{
A(int a1, int a2)
{
cout << "Creating A(" << a1 << ", " << a2 << ")" << endl;
}
virtual char const * whoAmI() const override
{
return "A";
}
};
struct B : public C
{
B(int b1, int b2)
{
cout << "Creating B(" << b1 << ", " << b2 << ")" << endl;
}
B(int b1, int b2, int b3)
{
cout << "Creating B(" << b1 << ", " << b2 << ", " << b3 << ")" << endl;
}
virtual char const * whoAmI() const override
{
return "B";
}
};
typedef int I;
Register<C, A, I, I> a("a");
Register<C, B, I, I> b("b");
Register<C, B, I, I, I> b3("b");
int main()
{
C* a = Factory<C, I, I>::instance()->create("a", 1, 2);
C* b = Factory<C, I, I>::instance()->create("b", 3, 4);
C* b3 = Factory<C, I, I, I>::instance()->create("b", 5, 6, 7);
cout << "I am a " << a->whoAmI() << endl;
cout << "I am a " << b->whoAmI() << endl;
cout << "I am a " << b3->whoAmI() << endl;
return 0;
}
这是你想要的吗?如果您不想处理函数参数,请使用辅助模板函数为您推断它们,如下所示:
template <typename BaseT, typename...ARGs>
BaseT* create(const string& name, ARGs&&...args)
{
return Factory<C, ARGs...>::instance()->create(name, forward<ARGs>(args)...);
}
int main()
{
C* a = create<C>("a", 1, 2);
C* b = create<C>("b", 3, 4);
C* b3 = create<C>("b", 3, 4, 5);
cout << "I am a " << a->whoAmI() << endl;
cout << "I am a " << b->whoAmI() << endl;
cout << "I am a " << b3->whoAmI() << endl;
return 0;
}
它的额外好处是允许通过明显的单个函数 API 提供多个构造函数签名(它看起来只是一个,但实际上是 N 其中 N 是您允许的不同签名的数量)。这都可以通过这个online demo.
查看您仍然需要使用我之前描述的相同注册,可以通过宏缩短。
如果这仍然不是您想要的,请在您的问题中添加更多细节。