我不知道你爲什麼厭惡編寫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)...
調用以實現完美轉發。它現在已被添加。
至於你以爲這是沒有用的,這裏是用完美的轉發和varidict模板允許特定類型的參數特定數量的特定工廠實例全面推行你的工廠:
#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查看。
您仍然需要使用與前面描述的相同的註冊,但可以通過宏縮短。
如果這是仍然不是你想要的,然後添加額外的細節到你的問題。
我認爲這樣做*完美*是不可能的;函數的參數實際上是編譯時與其他語言(如Java或C#)的對比。 (他們可以通過反射動態調用一個函數)當然C++有*編譯時*反射,但是你想動態地調用函數。我建議模仿這些運行時反射:你可以使用類似'void * create(const std :: vector
ikh
2015-03-19 10:26:04
如果允許某種動態初始化,通過引入一個基本上是'boost :: any'列表的'config'類,並且始終允許它作爲將要創建的類的單個參數,我會輕鬆得多。 – filmor 2015-03-19 15:16:29
'create()'函數有什麼問題? – Adrian 2015-03-19 20:05:58