现在我们已经可以很方便的组装我们所需要的粒子结构了,但任存在一个问题。每当我们需要加入一个新的粒子部分时必须自定义一个类似SParticlePos的结构,如果我们设计的是一个粒子的拆分部分非常多的系统这无疑是一件非常枯燥的差事。有没有什么方法可以解决呢?我们不妨定义一个泛型的粒子部分:
// 粒子部分
template<
typename _Type
> struct TParticlePart {
_Type m_Value;
};
我们通过_Type模板参数来指定粒子部分的类型,比如原先的SParticlePos我们在使用D3D的平台上可以写成TParticlePart< D3DXVECTOR3 >。这样的设计看似很好,其实隐藏着一个问题。如我们在D3D平台上定义一个如下的粒子:
typedef TParticlePolicy<
boost::mpl::vector<
TParticlePart< D3DXVECTOR3 >, // 位置
TParticlePart< D3DXVECTOR3 >, // 速度
TParticlePart< D3DXCOLOR >, // 颜色
TParticlePart< FLOAT >, // 寿命
>
> tMyParticle;
tMyParticle p;
此时我们要访问粒子的位置部分应该写成p.m_Value,但如果你这样写编译器就会抱怨产生了歧义。原因是不论你需要访问的是位置、速度、颜色还是寿命都应该写成p.m_Value,如何告诉编译器你真正想要访问的部分呢?这就需要引入一个用于区分不同部分的TPartDiff模板类,同时对TParticlePartHolder和TParticlePolicy做一些修改:
// 区分粒子的不同部分
template<
class _Part,
class _Diff
> class TPartDiff : public _Part
{};
// 粒子组装器
template<
class _PartIter,
class _PartsVector
> class TParticlePartHolder
: public TPartDiff<
boost::mpl::deref< _PartIter >::type,
boost::mpl::int_< _PartIter::pos::value >
>
, public TParticlePartHolder< _PartIter::next, _PartsVector >
{};
template<
class _PartsVector
> class TParticlePartHolder< boost::mpl::end< _PartsVector >::type, _PartsVector >
: public boost::blank
{};
// 粒子
template<
class _PartsVector
> struct TParticlePolicy
: public TParticlePartHolder< boost::mpl::begin< _PartsVector >::type, _PartsVector >
{
typedef _PartsVector tPartsVector;
// 部分数
static const int s_ciNumOfParts = boost::mpl::size< _PartsVector >::type::value;
// 获取一个粒子部分
template< size_t nIndex >
TPartDiff< boost::mpl::at_c< _PartsVector, nIndex >::type, boost::mpl::int_< nIndex > >& Part( void ) {
return *this;
}
// 获取一个粒子部分
template< size_t nIndex >
const TPartDiff< boost::mpl::at_c< _PartsVector, nIndex >::type, boost::mpl::int_< nIndex > >& Part( void ) const {
return *this;
}
TPartDiff接受两个模板参数第一个是形如TParticlePart< D3DXVECTOR3 >的粒子部分,第二个是用此粒子部分在粒子定义中的索引位置转换的类型(通过boost::mpl::int_<>可以将常量转换为类型)用于区分。TParticlePartHolder不再直接继承粒子部分,而是通过TPartDiff继承带有区分的粒子部分。TParticlePolicy引入了一个公共模板成员函数Part()用于访问不同的粒子部分,其有一个模板参数用于指定所需要访问的粒子部分的索引,这个函数还有一个Const版本。如果我们要访问以上定义的tMyParticle类型的粒子p的不同部分我们可以写成:
p.Part< 0 >().m_Value; // 访问粒子的位置
p.Part< 1 >().m_Value; // 访问粒子的速度
p.Part< 2 >().m_Value; // 访问粒子的颜色
p.Part< 3 >().m_Value; // 访问粒子的寿命