2012-12-09 21 views
6

私はhereのようなコードを書こうとしていますが、BoostなしではC++ 11の機能を使用しています。タイプ形質を使用して条件付きコンパイルを行うにはどうすればよいですか?

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'は真でなければならず、正しいコンパイルパスを選ぶべきです。 – 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

@タウラン:これは*プレーンテンプレートの特殊化ですね。何か不足していますか?または、オーバーロードされた関数を参照していますか?関数テンプレートは専門化を非常に好きではありません... –

+0

Nice answer man。リンクされた質問にはこれがありません。 – 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(頂点がnormal、texcoord、color)を持っているかどうかを考えてみましょう。型特性で 'hasNormal'フラグをオンまたはオフに設定するのではなく、通常の型で' _ Vertex'型をテンプレート化する必要があります。 – bobobobo

+0

状況によって異なります。この場合、私は他の解決方法も選びます:) – tauran

関連する問題