2012-12-09 64 views
6

我試圖編寫代碼,如here,但使用C++ 11功能,沒有Boost。如何使用類型特徵來進行條件編譯?

this example工作,我試圖定義response_trait,並基於條件編譯特性的結果。我該如何做這項工作?

#include <vector> 
using namespace std ; 

struct Vector{ float x,y,z ; } ; 
struct Vertex { Vector pos ; } ; 
struct VertexN { Vector pos, normal ; } ; 
struct Matrix {} ; 

template <typename T> 
struct response_trait { 
    static bool const has_normal = false; 
} ; 

template <> 
struct response_trait<VertexN> { 
    static bool const has_normal = true; 
} ; 

template <typename T> 
struct Model 
{ 
    vector<T> verts ; 

    void transform(Matrix m) 
    { 
    for(int i = 0 ; i < verts.size() ; i++) 
    { 
     #if response_trait<T>::has_normal==true 
     puts("Has normal") ; 
     // will choke compiler if T doesn't have .normal member 
     printf("normal = %f %f %f\n", verts[i].normal.x, verts[i].normal.y, verts[i].normal.z) ; 
     #else 
     puts("Doesn't have normal") ; 
     printf("pos = %f %f %f\n", verts[i].pos.x, verts[i].pos.y, verts[i].pos.z) ; 
     #endif 
    } 
    } 

} ; 

int main() 
{ 
    Matrix m ; 
    Model<Vertex> model ; 
    model.verts.push_back(Vertex()) ; 
    model.transform(m) ; 

    Model<VertexN> modelNormal ; 
    modelNormal.verts.push_back(VertexN()) ; 
    modelNormal.transform(m) ; 
} 
+0

您能否讓您的問題自成一體並描述您想要實現的目標? –

+1

它是自包含的。 '#if''T'有'.normal'成員,'response_trait' has_normal'應該是true,並且應該選擇正確的編譯路徑。 – bobobobo

+0

除非我完全誤解了類型特徵。相關的問題是我的出發點,但我不知道我是否採取了錯誤的方式。 – bobobobo

回答

15

你可以嘗試這樣的事:

void transform_impl(Matrix const & m, std::true_type const &) 
{ 
    // has normal 
} 

void transform_impl(Matrix const & m, std::false_type const &) 
{ 
    // doesn't have normal 
} 

template <typename T> 
void transform(Matrix const & m) 
{ 
    transform_impl(m, response_trait<T>()); 
} 

你只需要修改你的特質一點:

#include <type_traits> 
template <typename> struct response_trait : std::false_type { }; 
template <> struct response_trait<VertexN> : std::true_type { }; 
+0

普通模板專業化有沒有優勢? – tauran

+1

@tauran:這*是*普通模板專業化,不是嗎?我錯過了什麼嗎?還是你指的是重載函數?功能模板不太喜歡專業化... –

+0

好的答案的人。鏈接的問題是缺少這一點。 – bobobobo

1

這裏是一個替代的解決方案,如果你的代碼可以投入函數不會讓你的設計變得繁瑣(例如,當你需要訪問你的對象的很多成員變量時)。當然,有時候最好專門研究整個班級。

#include <vector> 
#include <stdio.h> 

using namespace std ; 

struct Vector{ float x,y,z ; } ; 
struct Vertex { Vector pos ; } ; 
struct VertexN { Vector pos, normal ; } ; 
struct Matrix {} ; 

template <typename T> 
void printVertex(T vert) 
{ 
     printf("Doesn't have normal") ; 
     printf("pos = %f %f %f\n", vert.pos.x, vert.pos.y, vert.pos.z) ; 
} 

template <> 
void printVertex(VertexN vert) 
{ 
     printf("Has normal") ; 
     printf("normal = %f %f %f\n", vert.normal.x, vert.normal.y, vert.normal.z) ; 
} 

template <typename T> 
struct Model 
{ 
    vector<T> verts ; 

    void transform(Matrix m) 
    { 
    for(int i = 0 ; i < verts.size() ; i++) 
    { 
     printVertex(verts[i]); 
    } 
    } 
} ; 

int main() 
{ 
    Matrix m ; 
    Model<Vertex> model ; 
    model.verts.push_back(Vertex()) ; 
    model.transform(m) ; 

    Model<VertexN> modelNormal ; 
    modelNormal.verts.push_back(VertexN()) ; 
    modelNormal.transform(m) ; 
} 
+0

這很聰明。我沒有考慮使用全局函數而不是成員函數。也許這就是爲什麼STL具有全局函數('std :: find'等)的功能 – bobobobo

+2

事實證明,這種方式有點麻煩,它會鼓勵更多類型的模板專門化,而不是使用類型特徵。考慮如果您有更多的頂點格式,VertexNC(頂點具有正常顏色),VertexNTC(頂點具有正常,texcoord,顏色)。你必須使用正常的模板專門化_every_'頂點類型,而不是在類型特徵中設置或打開'hasNormal'標誌。 – bobobobo

+0

這取決於情況。在這種情況下,我會選擇其他解決方案:) – tauran