0

给定:(代码减少到合理的最小值)

// 成员类型

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++ 配置每个渲染。此外,这几乎是我第一次使用模板。

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

预期用途是创建大量粒子,所有类型完全相同,并以尽可能快的速度处理和渲染它们。:)

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

4

3 回答 3

3

嗯,首先,您似乎在滚动很多自己的东西。我会研究Boost::MPL来替换,比如 Base 选择模板,并用继承来继承向量。

其次,您使用的是“const static bool hasSpeed = true;” 很多; 在我的编程中,我通常更喜欢 typedefed trait,类似于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 来禁用不适用于给定粒子的代码。它可能会非常快(因为在编译时会发生很多工作),但是您会有巨大的、难以阅读的错误语句(对于模板新手来说不太容易理解)。

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

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

// 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 */ }
于 2009-05-28T15:42:15.067 回答
2

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

于 2009-05-28T15:15:37.773 回答
1

一件事,您在 Particle 的模板定义中使用了 USE_SIZE 两次。

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

于 2009-05-28T14:53:00.407 回答