这是对@MichaelAnderson 解决方案的补充。
做同样的FactoryBonusModifier
事情,但不要enum
在 python 中生成 and 数组。在模板元编程中进行。
首先,一些样板。这些东西只是模板元编程的工具包:
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
,我们可以将其与参数包扩展一起使用来迭代参数包并对参数包中的每个元素执行操作。与其他 hack 相比,我更喜欢它,因为它很容易编写并且带来的惊喜更少。
一旦我们有了这套基本的工具,我们就可以很容易地编写一个工厂工厂:
// 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
value n
,则MetaFactory.GetItem(n)
返回一个指向FactoryBonusModifier
基类的指针(nullptr
如果n
超出范围)。
工厂生命周期由MetaFactory
对象的生命周期管理。
简而言之,代码生成通常在模板之前用于此类事情。但是可变参数模板使整数<->
类型映射变得非常容易,并且可以生成令人印象深刻的代码。
作为附带的好处,这个版本包括许多 python 生成的版本没有的类型安全。我什至可以编写一个函数n
,并调用传入的函子,并使用指向相关工厂的正确类型的指针,从而产生更多的类型安全性。
现在,如果您有超过 100 种奖励类型,则此技术会变得更加困难,因为已达到编译器递归限制。即使这样,也有一些技术允许以这种方式处理 1000 种类型的列表(但是,它们更尴尬)。
上面的代码还没有编译,所以几乎可以肯定包含错误,但基本设计是可靠的——我以前做过。