2011-11-02 115 views
5

我有一個模板基類是這樣的:將模板函數限制爲基類和派生類型?

template<typename T, std::size_t Size> 
class VectorT 
{ 
public: 
    typedef T data_type; 
} 

和一些專業派生類:

template<typename T> 
class Vector2d : public VectorT<T, 2U> 
{ // some specialised functions } 

template<typename T> 
class Vector3d : public VectorT<T, 3U> 
{ // some other specialised functions } 

這些做工精細。 Howerver,我爲操作員提供了一些獨立的功能。例如:

template<typename T, size_t Size> 
VectorT<T, Size> operator*(T lhs, const VectorT<T, Size>& rhs) 
{ 
    ... 
} 

不幸的是,這些沒有爲我的派生類的工作,因爲他們返回VectorT<T, Size>而不是Vector2d<T>的。

所以我試圖用

template<V> 
V operator*(typename V::data_type lhs, const V& rhs) 
{ 
    ... 
} 

,這工作得很好,但它可能會導致歧義,因爲它在其他任何一個成員DATA_TYPE吮吸。

我該如何解決這個問題:我該如何編寫類型安全函數,這些函數只能用於我的向量基或者任何派生類?

我想解決不得不重新聲明和重新定義子類的操作符。

回答

7

您可以添加又一個基類,一個是獨立的模板參數,並使用SFINAE禁用的其他類型的呼叫比從這樣的基礎衍生:

struct VectorBase {}; 

template< typename T, std::size_t Size > 
class VectorT : public VectorBase { ... } 

template< typename V > 
typename boost::enable_if< boost::is_base_of< VectorBase, V >, V >::type 
operator*(V lhs, V const& rhs){ ... } 

注意is_base_of< X, X >總是true,所以這個函數可以用於比所需類型更多的類型,即基類VectorBase

如果您正在使用實現TR1的編譯器,則可以在兩個使用位置替換boost::std::

+1

謝謝你,這是今晚你第二次給我一個涉及SFINAE的答案;我認爲這是我所知道的空白所在!我不確定enable_if是如何工作的,但是這個工作非常好。再次感謝你。 – DanDan

+0

@Kballo:關於用'std ::' - 替換'boost ::'請注意'std :: enable_if'對'boost :: enable_if_c'是一個嚴格的等價物,因此你必須「解開」切換到'std ::'時,您自己的'is_base_of'的值''成員。 –

1

你處於一種不尋常的情況,沒有「好」的方式。您可以:

  1. 檢查在運行時類型(或編譯時,升壓也許可以做到這一點)
  2. 乘坐VectorT<>&並用它來代替創建函數中一個新的VectorT並將其返回。這樣,您也可以通過參考獲得VectorT的子類。這將使你不得不使用一個函數,而不是一個操作符。
  3. 做什麼K-ballo說。
+1

我最喜歡選項3:P –