使用模板减少班级规模的合理方法?

时间:2009-05-28 13:48:28

标签: c++ optimization templates size

鉴于:(代码减少到合理的最低值)

// 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大小增加1,为什么会这样?
  • 这里有什么模式,习语等有用吗?

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

我应该提一下,我正在研究的这个粒子系统不是“实时”,将处理大量的粒子,我将从C ++配置每个渲染。此外,这几乎是我第一次使用模板。

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

预期的用途是创建一个巨大的粒子,所有粒子都完全相同,然后处理和渲染它们,尽可能快地使代码运行。 :)

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

3 个答案:

答案 0 :(得分:3)

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

其次,你正在使用“const static bool hasSpeed = true;”很多;在我的编程中,我通常更喜欢类型为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 */ }

答案 1 :(得分:2)

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

答案 2 :(得分:1)

有一件事,你在模板定义中使用USE_SIZE两次。

您可能还会考虑使用flyweight模式,具体取决于数据的重复性。 http://www.boost.org/doc/libs/1_39_0/libs/flyweight/doc/tutorial/index.html