2010-07-20 116 views
0

我試圖理解ublas中使用的模式。 模式是這樣的:C++繼承模式+ CRTP

struct vector : vector_expression<vector> 

其中vector_expression是這樣的:

template<class E> 
class vector_expression { 
... 
// no constructor or E pointer/reference in class 
// 
const E &operator()() const { 
     return *static_cast<const E*>(this); 
} 

完整的源代碼是在這裏: http://www.tena-sda.org/doc/5.2.2/boost/dd/d44/vector__expression_8hpp-source.html#l00088

我的問題是,如何做*static_cast<const E*>(this)工作?它依賴於繼承嗎?

下一個問題:如果 我得到

template<class E> 
class vector_expression2 : private vector_expression<E> 
{ 
    //friend class ublas::vector_expression<E>; // this is the fix 
    typedef vector_expression<E> base; 
    const E& operator()() const { return base::operator()(); } 
}; 

我得到關於靜態鑄造人跡罕至vector_expression基地編譯器錯誤。爲什麼會發生?

謝謝

+0

對不起,我搞砸了原來的帖子,並作出澄清 – Anycorn 2010-07-20 05:03:17

回答

2

這是爲了約束函數模板一招 - 限制類的類型。有很多像載體表達,標量表達式,矩陣式等概念,如果你要編寫一個標量乘以一個向量函數模板,你可以嘗試寫

template<typename V, typename S> 
some_type operator*(V v, S s); // vector * scalar 

template<typename V, typename S> 
some_type operator*(S s, V v); // scalar * vector 

但這行不通因爲兩個聲明本質上是等價的,並且沒有人說V是一個向量表達式,S應該是一個標量表達式。那麼,什麼的uBLAS開發商確實是使用CRTP來約束這些模板:

template<typename V, typename S> 
some_Type operator*(vector_expression<V> ve, scalar_expression<S> se); 

爲了使這項工作的所有的標量表達式■找從scalar_expression<S>派生和所有矢量表達式V是從vector_expression<V>派生。這樣,只有當第一個操作數是一個向量的表達式而第二個參數實際上是標量的表達式時才考慮這個操作符。你可以重載這個函數模板,第二個交換兩個參數,一切正常。

現在,爲了能夠訪問V和S(派生類型)中的任何內容,我們需要從基類轉換爲派生類。這是基類中的轉換運算符的用途。由於基類知道派生類(它是一個模板參數),所以這不是問題。選擇最弱的演員可以讓演員避免失誤。這是static_cast。它可以用來將base *轉換爲derived *而沒有任何重大的開銷。

我不明白你想用什麼代碼做

template<class E> 
class vector_expression2 : private vector_expression<E>; 

如果你想編寫自己的矢量表達式作爲一個模板,你會做這樣的:

template<class E> 
class my_parameterized_vector_expression 
: public vector_expression<my_parameterized_vector_expression<E> >; 

我認爲它不適用於私人繼承。如果在此處使用私有繼承,至少所有將矢量表達式作爲參數的函數模板將無法從基類訪問轉換運算符。

+0

謝謝。 我正在爲cublas構建一座橋樑,我需要在重新使用框架的同時防止轉換爲ublas表達式。 所以我用繼承來控制訪問 – Anycorn 2010-07-21 15:27:09

1

您指的可訪問性錯誤沒有意義。 vector_expressionstruct,函數調用operator()是公開的。也許你試圖調用vector_expression2::operator()?這會給你一個錯誤,因爲你將該運算符定義爲私有。

解決您的問題可能會比您想象的更簡單。如果你看一下通過的uBLAS源代碼,你會看到派生vector_expression任何類通過自己作爲模板參數:

template<class M> 
class matrix_row: public vector_expression<matrix_row<M> > { 
}; 

這意味着,由於模板參數從vector_expression派生vector_expression可投的模板參數本身,因此*static_cast<const E*>(this)的作品,這只是一個奇特的方式來說*((const E*)this)

嘗試重寫vector_expression2類,像這樣:

template<class E> 
class vector_expression2 : public vector_expression<vector_expression2<E>> 
{ 
}; 
+0

所以......這是類似使用模板實現的非常簡單的動態投射? 這種模式的名稱是什麼? – Anycorn 2010-07-21 03:42:16

+1

從派生類作爲模板參數派生的類的整個動作是CRTP - 好奇地重複出現的模板模式。這個特定的運算符可以被認爲是一種編譯安全的向下轉換到派生類型,否則你需要'dynamic_cast'和RTTI。 – 2010-07-21 05:43:47