2011-12-23 45 views
2

我想要一個系統的設計,其中用戶可以將其自己的類定義爲多個預定義組件的聚合,然後讓此類工作與我提供的算法。我試圖用編譯時和/或基於模板的方法來做到這一點,而不是運行時多態或虛函數,因爲在這種情況下性能很重要。定義/使用從預設組件構建的類(在C++中)

例如,考慮我有許多可用於構建3D頂點的組件。我將定義這些組件爲位置,正常,顏色等,然後​​用戶將能夠(通過多重繼承,組合或什麼?)來定義一個頂點,如PositionAndColorVertex,它只有位置和顏色,但沒有正常。現在,我提供了一個功能,做一個百萬,這些頂點的矢量一些處理:

template<typename UsersVertexType> 
void myProvidedAlgorithm(std::vector<UsersVertexType> input) 
{ 
    if(vertex has a position) 
     //do stuff with position 
    if(vertex has a normal) 
     //do stuff with normal 
    if(vertex has a color) 
     //do stuff with color 
} 

現在,我不知道UsersVertexType將是什麼樣子,但它會從我的組件來構建。我的功能需要對每個組件做些事情,但前提是它們存在。什麼是表達這種優雅和快速(編譯時間)的方式?

當然,我可以爲每種類型定義一個基類,讓用戶從所需基類繼承,然後使用dynamic_cast檢查哪些組件已實現,但這正是我想要的那種運行時方法避免。也許我可以在編譯時檢查這種繼承關係(編譯器應該知道UsersVertexType實際上是什麼,對吧?)。

也許我的組件應該用C++概念或策略表達?我也看到了mixin的討論,但不確定這些是否有用。用戶類應該使用多重繼承還是組合?也許我應該以某種方式將一組標誌放入用戶類中,指出它包含的內容?你將如何設計這個系統?

感謝您的任何見解!

說明:與我的previous question有相似之處,但我在此退一步尋找更高級別的設計選項/替代方案。

+0

重塑Boost Graph Library? – sehe

+0

在用戶類上設置標誌聽起來像個好主意。帶有OR的單個額外變量會檢查每個元素的標誌或更好,如果您檢查標誌組合,則直接檢查該數字。 – ivymike

回答

2

性狀和模板專業化。

#include <iostream> 
template <typename V> struct traits; // Primary template. 

然後定義一個版本與位置組件的頂點和一個頂點而不用:

template <typename Vertex, bool has_position=traits<Vertex>::has_position> 
struct some_position_op; 

template <typename Vertex> struct some_position_op<Vertex,false> { 
    void operator()() { std::cout << "has no position.\n"; } 
}; 

template <typename Vertex> struct some_position_op<Vertex,true> { 
    void operator()() { std::cout << "has position.\n"; } 
}; 

最後,您定義的每個頂點類型,可以實現一個traits類:

struct MyVertexWithPosition {}; 
template <> 
struct traits<MyVertexWithPosition> { 
    static constexpr bool has_position = true; 
}; 


struct MyVertexWithoutPosition {}; 
template <> 
struct traits<MyVertexWithoutPosition> { 
    static constexpr bool has_position = false; 
}; 

...和樂趣:

template <typename Vertex> 
void shade (Vertex const &vtx) { 
    some_position_op<Vertex>()(); 
} 

int main() { 
    shade (MyVertexWithPosition()); 
    shade (MyVertexWithoutPosition()); 
} 

你也可以專門設計功能模板,但必須犧牲你的shade功能的一些可讀性。

+0

好的,謝謝,我想我可以使用這樣的東西。 sehe的回答在使用特質時也是正確的,但我會接受這個作爲一個更完整的例子。 – PolyVox

4

通常的模式是使用type_traits,和/或使用專門用於UserVertexType的獨立功能模板。

添加一點SFINAE重載選擇魔術和瞧:你已經發明瞭模板元編程和Boost圖庫。

小想法樣本:

template <typename VertexType> 
struct vertex_traits // default vertex_traits: 
{ 
    typename unused_tag position_type; 
    enum { 
     hasNormal = 0 // treat as 'boolean' 
     hasColor = 0 
    }; 
}; 

template <typename V> vertex_traits<V>::position_type& position(V&); 

的想法是,通過使通用的東西來定義類你不強加給用戶的選擇頂點類型的任何不必要的限制(他們可能只是使用std ::對,他們可能只是通過第三方類型和裝飾它與您的圖形庫等使用)

谷歌:「非成員函數如何提高封裝」(由斯科特·邁耶)

+0

好的,這是很好的信息。除了您提供的BGL/Meyers鏈接外,我還遇到了[在OpenMesh中定義自定義網格](http://openmesh.org/Documentation/OpenMesh-2.0-Documentation/mesh_type.html),這也需要一個特性基於方法。我會進一步看看這些。 – PolyVox