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

だからここに私の質問があります:

  • これは、クラスのサイズを自動的に縮小するための合理的なアプローチですか?
  • 2 つのプロパティからのみ継承すると、Particle のサイズは 1 になります。それを超えると、EmptyBase を追加するたびにサイズが 1 ずつ増加します。なぜですか?
  • ここで役立つパターンやイディオムなどはありますか?

計画は、存在するプロパティに基づいて粒子の処理を自動化するテンプレートを作成することです。

私が取り組んでいるこのパーティクル システムは「リアルタイム」ではなく、膨大な量のパーティクルを処理すること、および C++ から各レンダリングを構成することを言及する必要があります。また、これはテンプレートを使用する最初の試みです。

編集: テンプレート アプローチを選択した理由は基本的に 2 つあります。2 つ目の理由は速度です。実行時に何も変更する必要がないので、テンプレートを使用して仮想関数や未使用のクラス メンバーなどのオーバーヘッドを削除できると考えました。

使用目的は、まったく同じタイプの無数のパーティクルを作成し、それらを処理してレンダリングし、コードを実行できる限り高速にすることです。:)

アイデアは、カスタム ファンクターをプラグインしてパーティクルを処理できる、高度に構成可能なシステムを用意することです。理想的には、パーティクルのプロパティは、実際に使用される場合にのみ有効になりますが、それが可能かどうか、またどのように可能かはわかりません。

4

3 に答える 3

3

うーん、まず、あなたは自分のものをたくさん転がしているようです。Boost::MPLを調べて、たとえば Base 選択テンプレートを置き換え、継承を使用してベクトルを継承します。

次に、「const static bool hasSpeed = true;」を使用しています。多くの; 私のプログラミングでは、通常はBoost::type_traitsのような typedefed トレイトを好みます。これらを使用して、コンパイル時に実行する関数を選択できます。その「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

3 番目に、ここで行っていることの多くは、最終的な用途をどうしたいかによって異なります。粒子を分離して、相互に変換できないタイプにしますか? このルートに進むと、ほぼすべての関数がテンプレートになり、boost::enable_if を使用して特定のパーティクルに適用されないコードを無効にすることができます。非常に高速になる可能性があります (コンパイル時に多くの作業が行われるため) が、巨大で読みにくいエラー ステートメントが表示されます (テンプレートを初めて使用する人にとってはアクセスしにくい)。

もう 1 つの非テンプレート ルートは継承です。粒子が必要とする一連の仮想関数を定義し、それらを継承元のクラスに分割します。あなたのコードからは、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

1つは、Particleのテンプレート定義でUSE_SIZEを2回使用することです。

データの反復性によっては、フライウェイトパターンの使用を検討することもできます。 http://www.boost.org/doc/libs/1_39_0/libs/flyweight/doc/tutorial/index.html

于 2009-05-28T14:53:00.407 に答える