這是增強一個以@ MichaelAnderson的解決方案。
照此FactoryBonusModifier
,但不產生蟒蛇的enum
和陣列。在模板元編程中進行。
首先,一些樣板。這東西是隻爲模板元編程工具包:
template<typename...>
struct type_list {};
// get the nth type from a list:
template<int n, typename list>
struct nth_type;
// the 0th type is the first type:
template<0, typename t0, typename... types>
struct nth_type<0, type_list<t0,types...>> {
typedef t0 type;
};
// the nth type is the n-1th type of the tail of the list:
template<int n, typename t0, typename... types>
struct nth_type<n, type_list<t0,types...>>:nth_type<n-1,type_list<types...>>
{};
// Get the index of T in the list. 3rd parameter is for metaprogramming.
template<typename T, typename list, typename=void>
struct index_in;
// If T is the first type in the list, the index is 0
template<typename T, typename t0, typename... list>
struct index_in<T, type_list<t0, list...>, typename std::enable_if<std::is_same<T,t0>::value>::type> {
enum {value = 0};
};
// If T is not the first type in the list, the index is 1 plus the index of T
// in the tail of the list:
template<typename T, typename t0, typename... list>
struct index_in<T, type_list<t0, list...>, typename std::enable_if<!std::is_same<T,t0>::value>::type> {
enum {value = index_in<T, type_list<list...>>::value+1};
};
// calls() on the arguments passed to it in order:
inline void do_in_order() {}
template<typename L0, typename... Lambdas>
void do_in_order(L0&& l0, Lambdas&&... lambdas) {
std::forward<L0>(l0)(); // std::forward is for insane corner cases, not usually needed
do_in_order(std::forward<Lambdas>(lambdas)...);
}
我們有type_list
,其中封裝了一個類型列表以繞過或操縱。我們在type_list
,nth_type
上有兩個操作,它從索引中提取一個類型,index_in
接受一個類型並返回它的索引。
最後,我們有一個名爲do_in_order
的幫助函數,我們可以通過參數包擴展來遍歷參數包,併爲參數包中的每個元素執行一個操作。我更喜歡其他黑客,因爲它很容易編寫,而且結果更少意外。
一旦我們有了這個基本的工具集,才能真正輕鬆地編寫一個廠廠房:
// bad name for this template. It takes the type list list and applies
// the producer template on each, then stores pointers to instances of those
// in an array of base pointers (well unique_ptrs). It also provides
// a type-to-index mapping, an index-to-instance mapping, and a type-to
// instance mapping:
template<typename list, template<typename>class producer, typename base>
struct mapping;
template<typename... Ts, template<typename>class producer, typename base>
struct mapping<type_list<Ts...>, producer, base>
{
enum Enum {
min_value = 0,
max_value = sizeof...(list)
};
template<typename T>
static Enum GetIndex() constexpr { return (Enum)index_in<T, type_list<Ts...>>::value; }
std::unique_ptr<base> Array[max_value];
mapping() {
do_in_order([&Array](){
Array[ GetIndex<Ts>() ].reset(new producer<Ts>());
}...);
}
// typed get:
template<typename T>
producer<T>* GetItem() const {
return static_cast<producer<T>*>(Array[GetIndex<T>].get());
}
// index get:
base* GetItem(std::size_t n) const {
if (n >= max_value)
return nullptr;
return Array[n].get();
};
這無助尚未。添加在邁克爾的回答是:
class FactoryBonusModifier
{
public:
/// Function to overload
virtual BonusModifierAbstract* createBonus() const = 0;
protected:
};
template<typename Bonus>
class Factory : public FactoryBonusModifier
{
public:
virtual Bonus* createBonus() const
{
return new Bonus();
}
};
再喂Factory
和支持的類型的列表,以mapping
:
type_list< ItemBonus, InheritBonus, TaxBonus, PerformanceBonus > BonusList;
typedef mapping< BonusList, Factory, FactoryBonusModifier > MetaFactory_t;
MetaFactory_t MetaFactory;
,我們正在做。
MetaFactory_t::Enum
是一種代表單個工廠的類型,以及它們在數組中的偏移量。要獲得給定獎勵類型的Enum
值,請提供MetaFactory_t::GetIndex<BonusType>()
。
如果您想要某個特定獎金類型的工廠,MetaFactory.GetItem<BonusType>()
將返回正確類型的指針Factory<BonusType>
。如果您有Enum
值n
,則MetaFactory.GetItem(n)
會返回指向FactoryBonusModifier
基類的指針(如果n
超出範圍,則返回nullptr
)。
工廠的生命週期由MetaFactory
對象的生存期管理。
簡而言之,代碼生成通常用於模板之前的這類事情。但variardic模板使整數<->
類型映射相當簡單,並允許相當令人印象深刻的代碼生成。
作爲一個附帶的好處,這個版本包含了許多python生成版本沒有的類型安全。我甚至可以寫一個需要n
的函數,並用指向正確問題工廠類型的指針調用傳入函數,從而生成更多的類型安全性。
現在,如果你有超過幾百種獎勵類型,這種技術變得更加困難,因爲編譯器遞歸限制被擊中。即使如此,仍有技術可以用這種方式處理1000種類型的清單(然而,它們更笨拙)。
上面的代碼沒有被編譯,所以幾乎肯定包含錯誤,但基本設計是堅實的 - 我以前做過。
我不會說這是嚴格重複的,因爲這特別涉及(至少部分)使用宏來達到目的,而另一個問題則沒有。 – CodeMouse92 2015-02-03 04:06:56