2012-12-09 11 views
6

Sto provando a scrivere codice come here ma utilizzando le funzionalità di C++ 11, senza Boost.Come si utilizzano i tratti del tipo per eseguire la compilazione condizionale?

Lavorando da this example, ho provato a definire un response_trait e una raccolta condizionale in locale sul risultato del tratto. Come posso fare questo lavoro?

#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

Potete per favore rendere la vostra domanda autonoma e descrivere cosa state cercando di ottenere? –

+1

È autonomo. '# if'' T' ha un membro '.normal',' response_trait' 'has_normal' dovrebbe essere vero, e dovrebbe essere scelto il percorso di compilazione corretto. – bobobobo

+0

A meno che non abbia completamente frainteso i tratti tipografici. La domanda collegata era il mio punto di partenza, ma non ho idea se l'ho presa nel modo sbagliato. – bobobobo

risposta

15

Si potrebbe provare qualcosa di simile:

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>()); 
} 

Hai solo bisogno di modificare il vostro carattere un po ':

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

Esiste un vantaggio per la specializzazione del modello semplice? – tauran

+1

@tauran: Questa * è * specializzazione del modello semplice, non è vero? Mi sto perdendo qualcosa? O ti riferisci alle funzioni sovraccariche? I modelli di funzioni non amano molto le specializzazioni ... –

+0

Nice answer man. La domanda collegata manca questo. – bobobobo

1

Ecco una soluzione alternativa se il codice può essere messo in funzioni senza rendere complicato il tuo progetto (ad esempio quando hai bisogno di accedere a molte variabili membro del tuo oggetto). Certo, a volte è preferibile specializzare l'intera classe.

#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

Questo è molto intelligente. Non pensavo di creare funzioni globali invece di funzioni membro. Forse questo è il motivo per cui l'STL ha le sue funzioni come funzioni globali ('std :: find', ecc.) – bobobobo

+2

Si scopre che in questo modo è un po 'più ingombrante, incoraggerà la specializzazione dei modelli di più tipi rispetto all'utilizzo di tratti tipo. Considera se hai un paio di altri formati vertici, 'VertexNC' (vertice con normale, colore),' VertexNTC' (vertice con normale, texcoord, colore). Dovresti template template _every_ 'Vertex' con un normale in esso, invece di impostare on o off il flag' hasNormal' nei caratteri type. – bobobobo

+0

Dipende dalla situazione. In questo caso sceglierei anche l'altra soluzione :) – tauran

Problemi correlati