2009-05-28 47 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 */ }