2009-05-28 48 views
0

给定:(代码减少到最小明智)使用模板减少课程大小的合理方法?

// MemberTypes

template 
< 
    typename SPEEDTYPE = float, 
    typename SIZETYPE = float, 
    typename ACCELERATIONTYPE = float 
> 
struct ParticleMemberTypes 
{ 
    typedef typename SPEEDTYPE SpeedType; 
    typedef typename SIZETYPE SizeType; 
    typedef typename ACCELERATIONTYPE AccelerationType; 
}; 

//属性

template <class T> 
class PSpeed 
{ 
public: 
    inline const typename T::SpeedType& GetSpeed() const { return v; } 
    inline void SetSpeed(const typename T::SpeedType& V) { v = V; } 
    const static bool hasSpeed = true; 
private: 
    typename T::SpeedType v; 
}; 

template <class T> 
class PSize 
{ 
public: 
    inline const typename T::SizeType& GetSize() const { return v; } 
    inline void SetSize(const typename T::SizeType& V) { v = V; } 
    const static bool hasSize = true; 
private: 
    typename T::SizeType v; 
}; 

template <class T> 
class PAcceleration 
{ 
public: 
    inline const typename T::AccelerationType& GetAcceleration() const { return v; } 
    inline void SetAcceleration(const typename T::AccelerationType& V) { v = V; } 
    const static bool hasAcceleration = true; 
private: 
    typename T::AccelerationType v; 
}; 

//空基和专业

(这是必要每个EmptyBase都是不同的类型,以避免多次从同一个基类继承)

template <typename P, typename T> struct EmptyBase {}; 
template <typename T> struct EmptyBase<PSpeed<T>, T> 
{ 
    const static bool hasSpeed = false; 
}; 
template <typename T> struct EmptyBase<PSize<T>, T> 
{ 
    const static bool hasSize = false; 
}; 
template <typename T> struct EmptyBase<PAcceleration<T>, T> 
{ 
    const static bool hasAcceleration = false; 
}; 

//基地选择模板

template <bool ENABLE, typename P, typename T> struct EnableBase; 
template <typename P, typename T> struct EnableBase<true, P, T> 
{ 
    typedef P Type; 
}; 
template <typename P, typename T> struct EnableBase<false, P, T> 
{ 
    typedef EmptyBase<P, T> Type; 
}; 

//粒子模板类

template 
< 
    bool USE_SPEED = false, 
    bool USE_SIZE = false, 
    bool USE_ACCELERATION = false, 
    typename T = ParticleMemberTypes<> 
> 
struct Particle : 
    public EnableBase<USE_SPEED, PSpeed<T>, T>::Type, 
    public EnableBase<USE_SIZE, PSize<T>, T>::Type, 
    public EnableBase<USE_ACCELERATION, PAcceleration<T>, T>::Type 
{ 
}; 

我们现在可以这样做:

using namespace std; 

Particle<> p1; 
Particle<true, true, true, ParticleMemberTypes<Vector3<double> > > p2; 

cout << "p1: " << sizeof(p1) << endl; 
cout << "p2: " << sizeof(p2) << endl; 

输出:

p1: 2 
p1: 32 

因此,这里是我的问题:

  • 这是一个合理的方法来自动减少一类的大小?
  • 如果我只从两个属性继承,粒子的大小是1,那么为每个额外的EmptyBase大小增加一个,为什么?
  • 是否有任何会在这里有用的图案,成语等?

该计划是编写模板,根据存在的属性自动处理粒子。

我应该提到我正在处理的这个粒子系统不是“实时”的,会处理大量的粒子,而且我将配置C++中的每个渲染。另外,这几乎是我第一次使用模板。

编辑: 我选择模板方法的原因基本上有两个:一个是好奇心 - 只是了解模板并探索它们的用法。第二个原因是速度。因为我不需要在运行时改变任何东西,我想我可以使用模板来消除虚拟功能和未使用的类成员等的开销。

预期用途是创建一个bazillion粒子,全部完全相同的类型,然后处理并渲染它们,尽可能快地让代码去。 :)

这个想法是有一个高度可配置的系统,我可以插入自定义函数来处理粒子。理想情况下,粒子的属性只有在实际使用时才会启用,但我还没有弄清楚是否可行。

+0

我毫不犹豫的问你发布更多的代码,但至少对我来说,你打算如何使用这些不同的粒子类型的例子将是有用的。 – 2009-05-28 15:46:40

+0

我只打算每个编译/渲染使用一个粒子类型,如果有帮助。 – 2009-05-28 17:10:36

回答

2

您知道具有不同参数的模板类型不同吗?也就是说,在您的代码中,p1和p2是不同类型的,因此不能存储在同一个集合中,分配给对方等。当然,您的应用程序可能不需要这样的等价。

+0

当然,我使用这个事实来创建不同的EmptyBase <...>类型,以避免来自同一类的多重继承。 – 2009-05-28 15:43:25

3

嗯,首先,你似乎在滚动很多你自己的东西。我会考虑Boost::MPL来替换,比如说Base选择模板,并且继承带有继承的向量。

其次,您正在使用“const static bool hasSpeed = true;”很多;在我的编程中,我通常更喜欢typedefed特征,类似于Boost::type_traits。您可以使用它们来选择要在编译时运行的函数。你可以避免这样做“EmptyBase”。

template <typename T> 
struct has_size; 

template <bool speed, bool accel, typename T> 
struct has_size< Particle<true, speed, accel, T> > : public true_type 
{ }; 

template <bool speed, bool accel, typename T> 
struct has_size< Particle<false, speed, accel, T> > : public false_type 
{ }; 


// given a particle typedef SomeParticle_t 

has_size<SomeParticle_T>::value 

第三,你在这里做的很多事情取决于你希望你的最终用法是什么;你想要粒子是分开的,不能相互转换的类型?如果你走这条路线,几乎每一个函数都会成为一个模板,你可以使用boost :: enable_if来禁用不适用于给定粒子的代码。它可能会非常快(因为在编译时会发生很多工作),但是你会有巨大的,难以阅读的错误语句(对于不熟悉模板的人而言不太可访问)。

另一种非模板路由是继承;你可以定义一个粒子需要的一组虚函数,然后将它们分解为你继承的类。从你的代码中不太清楚你期望能用粒子做什么。这些错误会更容易理解,但代码可能较慢(更多的工作转移到运行,并会使您的对象大)

下面是一个代码示例来说明差异:

// Using templates 
template <typename particle> 
typename boost::enable_if< has_accel<particle>, typename particle::speed_type >::type 
calculate_future_speed(const particle& t) 
{ /* do your acceleration calculation */ } 

template <typename particle> 
typename boost::enable_if< boost::and_< has_speed<particle>, 
             boost::not_< has_accel<particle> >, 
         typename particle::speed_type >::type 
calculate_future_speed(const particle& t) 
{ /* no acceleration, so no calculation! just return the speed*/ } 

template <typename particle> 
typename boost::enable_if< boost::not_< has_speed<particle>, 
         typename particle::speed_type >::type 
calculate_future_speed(const particle& t) 
{ return 0; /* Has no speed, and no acceleration */ }