2013-07-12 108 views
3

我有以下幾點:C++:擴展模板類

template<typename T> class CVector3 
{ 
    CVector3<T> &normalize(); 
    // more stuff 
}; 

typedef CVector3<float> Vector3f; 
typedef CVector3<double> Vector3d; 

我基本上要添加一個方法,尖山(),它返回一個struct Point3f如果T = float和一個結構三維點如果T =雙重。我試着用替換兩個類型定義:

class Vector3f: public CVector3<float> 
{ 
    Point3f toPoint() const; 
}; 

class Vector3d: public CVector3<double> 
{ 
    Point3d toPoint() const; 
}; 

這是不行的,但是,因爲現在歸()被打破:它不再返回Vector3f,但CVector3 <浮動>,這與Vector3f不兼容,因爲它實際上是基類。我可以爲基類中的normalize()和任何其他公共方法添加包裝器方法,但我不想這樣做,因爲這會使這些類保持乏味。

我也試圖把類型定義回並添加模板定義之外:

template<> 
Point3f CVector3<float>::toPoint() const; 

template<> 
Point3d CVector3<double>::toPoint() const; 

這並不編譯,因爲尖山()沒有模板定義內部聲明。由於返回類型Point3f/Point3d,我無法將其放入內部。

我該怎麼做?任何幫助是極大的讚賞!

+0

''Point3f/Point3d'實例化嗎? – jrok

+0

不,它們是簡單的結構。 –

+0

也許CRTP ...? –

回答

0

感謝您的答覆,我現在已經想出了一個辦法,應該工作:

template<typename T, typename P> class CVector3 
{ 
    CVector3<T, P> &normalize(); 
    // more stuff 

    P toPoint() const; 
}; 

typedef CVector3<float, Point3f> Vector3f; 
typedef CVector3<double, Point3d> Vector3d; 

我要試試這個並告訴你它以後是否有效。乾杯!

編輯:是的,它的工作!我不得不定義尖山()這樣的:

template<> 
Point3f CVector3<float, Point3f>::toPoint() const 
{ 
    Point3f pt = { x, y, z }; 
    return pt; 
} 

你用特質的答案是肯定的更通用的解決方案,但由於Point3f是Vector3f自然掛件,我喜歡第二個模板參數更好。

3

你可以使用traits風格的助手類。

template<typename T> CVectorTraits {}; 
template<> CVectorTraits<double> { typedef Point3d PointType; } 
template<> CVectorTraits<float> { typedef Point3f PointType; } 

template<typename T> class CVector3 
{ 
    CVector3<T> &normalize(); 
    // more stuff 
    typename CVectorTraits<T>::PointType toPoint() const; 
}; 
+0

謝謝!這可能是一般的解決方案。試圖理解這一點讓我想到另一種解決方案,在我的情況下效果很好,並且更簡單一點,請參閱下文。 –

1

您可以使用類型性狀:

template<typename T> 
struct VectorTraits; 

template<> 
struct VectorTraits<float> { 
    typedef Point3f Point; 
}; 
template<> 
struct VectorTraits<double> { 
    typedef Point3d Point; 
}; 

template<typename T> class CVector3 
{ 
    CVector3<T> &normalize(); 

    typename VectorTraits<T>::Point 
    toPoint() const; 

    // more stuff 
}; 

typedef CVector3<float> Vector3f; 
typedef CVector3<double> Vector3d; 
+0

謝謝!這可能是一般的解決方案。試圖理解這一點讓我想到另一種解決方案,在我的情況下效果很好,並且更簡單一點,請參閱下文。 –

0

您可以改善客戶端的語法,並強制執行約束以確保客戶端不會因使用專業化而導致模板參數錯誤。

struct Point3f { float x, y, z; }; 
struct Point3d { double x, y, z; }; 

// Base template toPoint returns Point3f. 
template<typename T, typename U = Point3f> 
class Vector3 
{ 
public: 
    Vector3& normalize(){ return Vector3(); } 
    U toPoint(){ return Point3f(); } 
}; 

// Specialization for double, toPoint returns Point3d. 
template<> 
class Vector3<double> 
{ 
public: 
    Vector3& normalize(){ return Vector3(); } 
    Point3d toPoint(){ return Point3d(); } 
}; 


TEST(TemplateTests2, Test3) 
{ 
    Vector3<float> v1; 
    Point3f p1 = v1.toPoint(); 

    Vector3<double> v2; 
    Point3d p2 = v2.toPoint(); 
} 
+0

感謝您的建議。在我的例子中,'clients'應該只使用typedef Vector3f和Vector3d,它們已經設置了正確的組合。 –