2009-06-01 22 views
1

Ich habe eine typische 'vector4' Klasse mit einem Operator float *, um es autocasting für gl * 4fv sowie []. Es gibt auch ‚const‘ Version für Optimierungen für den Compiler sowie const refrences, und das funktioniert gut:Rekursiver Typ Casting

typedef struct vec4 
{ 
    ... 

    // ----------------------------------------------------------------- // 

     // Cast operator, for [] 
    inline operator float*() { 
     return (float*)this; 
    } 

     // Const cast operator, for const [] 
    inline operator const float*() const { 
     return (const float*)this; 
    } 

    // ----------------------------------------------------------------- // 

    ... 

     // Vertex/Vector 
    struct { 
     float x, y, z, w; 
    }; 

      // Color 
    struct { 
     float r, g, b, a; 
    }; 
} vec4; 

Mein Problem ist, wenn ich ein ‚MATRIX4‘ Klasse jetzt codiert, mit Bedienungs vec4 *, die unterstützt Extrahieren von Zeilen aus der Matrix, und haben auch den "Nebeneffekt" der Matrix [] [] Operator, was nett ist.

typedef struct mat4 
{ 
    ... 

    // ----------------------------------------------------------------- // 
      // Cast operator, for [] 
    inline operator vec4*() { 
     return (vec4*)this; 
    } 

     // Const cast operator, for const [] 
    inline operator const vec4*() const { 
     return (const vec4*)this; 
    } 
    // ----------------------------------------------------------------- // 

    private: 
     float f[16]; 
} mat4; 

Meine Frage ist, warum nicht der Compiler erkennt die Fähigkeit, eine MAT4 zu konvertieren * zu schweben? Ich würde vermuten, dass das Erbe von mat4 -> vec4 -> float * vernünftig ist, aber es scheint nicht so. Es kam mir in den Sinn, dass der Compiler es als MAT4 sehen könnte -> vec4 * -> float *, die nicht definiert ist, aber diese Annahme war ungültig, da

den Bediener definieren
inline operator const vec4() const { 
    return (vec4)*this; 
} 

nicht funktioniert, und Aufruf von glMultMatrixf (mat4 (...)); (Zum Beispiel) erzeugt die gleiche Fehlermeldung wie ohne den Operator.

definieren Operator float * in MAT4 ist natürlich unmöglich, denn das ist die Fähigkeit zu beseitigen [verwenden] [] (mehrdeutige Operatoren)

Irgendwelche Lösungen dafür? oder muss ich jedes Mal, wenn ich autocastieren möchte, manuell nach vec4 umwandeln? Auto-Casting ist ein wirklich nettes Feature und interpoliert den Code mit OpenGL sauber.

+0

Das 'inline' Schlüsselwort wird nicht in Klassen-/Struct-Deklarationen benötigt. – n0rd

+0

Wenn es eine Möglichkeit zur automatischen Konvertierung für Ihr Problem gäbe, hätten Sie bereits ein mehrdeutiges Operatorproblem mit [] [], als ob Sie in mat4 den Operator float * definiert hätten. –

+0

GCC 4.3.x scheint keine Probleme zu haben, es verwendet operator [] für [] [] und operator const float * für die const float * akzeptierende Funktion. MSVC ist das Problem, also suche ich eine andere Problemumgehung. – LiraNuna

Antwort

1

... Eine dieser Regeln ist, dass keine Folge von Umwandlungen darf enthalten mehr als eine benutzerdefinierte Konvertierung (dh ein Aufruf an einen einzelnen Argumentkonstruktor oder einen impliziten Typkonvertierungsoperator). - Effektiver C++, Scott Meyers

Sie könnten Operator [] für vec4 und mat4 überladen.

struct vec4 
{ 
    float& operator[](int index) { return f[index]; } 
    const float& operator[](int index) const { return f[index]; } 

    operator float*() { return f; } 
    operator const float*() const { return f; } 

    float f[4]; 
}; 

struct mat4 
{ 
    vec4& operator[](int row) { return v[row]; } 
    const vec4& operator[](int row) const { return v[row]; } 

    operator float*() { return f; } 
    operator const float*() const { return f; } 

    union 
    { 
     vec4 v[4]; 
     float f[16]; 
    }; 
}; 

int main(void) 
{ 
    mat4 m; 
    ::memset(&m, 0, sizeof(mat4)); 
    m[0][1] = 1; 
    cout << m[0][1] << endl; // it prints 1. 

    return 0; 
} 
+0

Das wird die Struktur auflösen - es gibt überhaupt keine Const-Konvertierung, was für gl * 4fv-ähnliche Funktionen gut wäre. Ich habe versucht, den Operator zu überlasten, und das funktioniert gut für GCC, aber MSVC Barfs und Fehler. Während ich mich nicht wirklich für MSVC interessiere, unterstütze ich immer noch portablen Code. – LiraNuna

+0

Ich habe gerade versucht zu zeigen, wie Operator [] überladen wird. Sie können problemlos eine konstante Version dieser Operationen hinzufügen. Ich habe den Code mit MSVC 2008 getestet und es war in Ordnung. Nicht sicher über GCC, obwohl. – young

+0

operator const float *() const {return f; } // so was. :) – young

3

C++ kann automatische Konvertierungen durchführen, führt aber standardmäßig keine zwei automatischen Konvertierungen durch.

Es wurde für unbeabsichtigte Bugs und Unklarheiten als zu günstig erachtet.

drei Optionen, die für Sie arbeiten können:

Explizit führen Sie das erste werfen Sie sich, wenn Sie eine float* aus einer Matrix wollen.

FuncThatWantsFloatPointer(*static_cast<Vec4*>(MyMatrix)); 

Implementieren eine direkte converstion zu float* in Ihrer Matrix-Klasse.

typedef struct mat4 
{ 
     ... 
     operator const float*() const 
     { 
       return *static_cast<Vec4*>(*this); 
     } 

} mat4; 

Implementieren operator[] in Ihrer Matrix und Vektor-Klassen, wenn Sie wie mit eckiger Klammer-Notation

typedef struct mat4 
{ 
     ... 
     const vec4& operator[] (size_t index) const 
     { 
       return static_cast<Vec4*>(*this)[index]; 
     } 

} mat4; 
+0

Und eine Abhilfe dafür existiert oder nicht? – LiraNuna

+2

Sie können die erste Konvertierung explizit vornehmen, sodass nur eine Konvertierung implizit ist. (* (Vec4 *) MyMatrix) kann in float * –

+3

konvertieren Sie können Ihrer Matrix-Klasse auch einen Operator hinzufügen, der direkt in float * konvertiert, indem Sie ihn zuerst in ein Vec4 * umwandeln. –