Frage

Ich bin mir ziemlich sicher, dass dies möglich ist, weil ich ziemlich sicher bin, ich habe es getan gesehen. Ich denke, es ist genial, aber ich werde gerne annehmen Antworten entlang der Linien von „dies ist eine schreckliche Idee, weil ____“.

Sagen wir eine grundlegende Struktur haben.

struct vertex
{
    float x, y, z;
};

Jetzt will ich Aliase auf diese Variablen implementieren.

vertex pos;
vertex col;
vertex arr;

pos.x = 0.0f; pos.y = 0.5f; pos.z = 1.0f;
col.r = 0.0f; col.g = 0.5f; col.b = 1.0f;
arr[0] = 0.0f; arr[1] = 0.5f; arr[2] = 1.0f;

Im Idealfall würde die dritte Syntax aus einem Array nicht unterscheidbar. Das heißt, wenn ich arr als Referenz Parameter eine Funktion erwartet eine Reihe von Schwimmern, in denen gesendet wird es Daten speichern (zB viele der OpenGL glGet Funktionen), wäre es gut funktionieren.

Was denken Sie? Möglich? Möglich, aber dumm?

War es hilfreich?

Lösung

Was ich tun würde, ist Accessoren machen:

struct Vertex {
    float& r() { return values[0]; }
    float& g() { return values[1]; }
    float& b() { return values[2]; }

    float& x() { return values[0]; }
    float& y() { return values[1]; }
    float& z() { return values[2]; }

    float  operator [] (unsigned i) const { return this->values_[i]; }
    float& operator [] (unsigned i)       { return this->values_[i]; }
    operator float*() const { return this->values_; }

private:
    float[3] values_;
}

Andere Tipps

Nameless verschachtelte Strukturen in einer Gewerkschaft sind nicht Standard C ++. Dies sollte jedoch funktionieren:

struct Vertex
{
private:
   typedef float Vertex::* const vert[3];
   static const vert v;

public:
   typedef size_t size_type;
   float x, y, z;

   const float& operator[](size_type i) const {
      return this->*v[i];
   }

   float& operator[](size_type i) {
      return this->*v[i];
   }

};

const Vertex::vert Vertex::v = {&Vertex::x, &Vertex::y, &Vertex::z};

EDIT: Etwas mehr Informationen. Die struct verwendet ein Array von 3 pointer-to-Daten-Elemente, die die Daten in den überlasteten [] Operatoren zuzugreifen.

Die Zeile „typedef Vertex schweben :: * const vert“ bedeutet, dass vert ein Zeiger auf ein Schwimmerelement der Vertex-Struktur ist. Die [3] bedeutet, dass es eine Anordnung von 3 von diesen ist. In dem überlasteten Operator [] wird dieses Array indiziert und das Zeiger-zu-Daten-Element dereferenziert und der Wert zurückgegeben.

Darüber hinaus sollte diese Methode funktioniert unabhängig von Verpackungsfragen - der Compiler ist es mag die Vertex-Struktur jedoch auf Pad und es wird funktionieren nach wie vor gut. Eine anonyme Vereinigung auf Probleme stoßen, wenn der Schwimmer anders verpackt werden.

eine Vereinigung verwenden?

union vertex
{
    struct { float x, y, z; };
    struct { float r, g, b; };
    float arr[3];
};

Ich würde es nicht empfehlen - es zu Verwirrung führen

.

hinzugefügt :

Wie von Adrian in seiner Antwort darauf hingewiesen, diese Vereinigung mit anonymen Strukturkomponenten nicht von ISO C ++ unterstützt. Es funktioniert in GNU G ++ (mit Beschwerden über nicht unterstützt werden, wenn Sie auf ‚-Wall -ansi -pedantic‘ drehen). Es erinnert an die Pre-Pre-Standard-C-Tage (pre-K & R 1. EDN), wenn Strukturelementnamen in allen Strukturen, einzigartig sein hatte, und Sie Notationen kontrahierten nutzen könnten, um ein innerhalb der Struktur versetzt zu bekommen, und man konnte verwenden Mitgliedernamen aus anderen Strukturtypen - eine Form der Anarchie. Als ich mit C gestartet (vor langer Zeit, aber nach K & R1), das war schon historische Nutzung.

Die Notation mit anonymen Gewerkschaftsmitgliedern (für die beiden Strukturen) gezeigt durch C11 (ISO / IEC 9899: 2011) unterstützt wird, aber nicht von früheren Versionen des C-Standard. Abschnitt 9.5 der ISO / IEC 14882: 2011 (C ++ 11) sieht für anonyme Gewerkschaften, aber GNU g++ (4.9.1) nicht akzeptieren, den Code mit -pedantic gezeigt, zu identifizieren "warning: ISO C++ prohibits anonymous structs [-Wpedantic]"

.

Da wird die Idee zu Verwirrung führen, ich bin nicht besonders besorgt darüber, dass es nicht Standard ist; Ich würde nicht den Mechanismus für diese Aufgabe verwenden (und ich würde die Verwendung anonymer Strukturen in einer Union leery sein, auch wenn es von Vorteil).


Ein Anliegen wurde erhöht:

  

Die drei (x-y-z, r-g-b und die Anordnung) kann auszurichten nicht unbedingt.

Es ist eine Vereinigung mit drei Elementen; die drei Elemente an der gleichen Adresse starten. Die beiden ersten sind Strukturen, die 3 Gleitkommawerte. Es gibt keine Vererbung und es gibt keine virtuellen Funktionen verschiedene Layouts geben usw. Die Strukturen werden angrenzend an die drei Elemente angelegt werden (in der Praxis, auch wenn die Standard-Polsterung erlaubt). Das Array beginnt ebenfalls an der gleichen Adresse und unter ‚kein padding‘ in den Strukturen, überlappen sich die Elemente, die die beiden Strukturen. Ich sehe nicht wirklich, dass es ein Problem sein.

Sie können mit einer Union erhalten diese wie andere erwähnt haben. Eine Überlastung Farbe und Position auf die gleiche Struktur wie kann dies nicht eine gute Idee (zum Beispiel das Hinzufügen von zwei Farben in der Regel bedeutet, dass Sie bis 1,0 sättigen wollen, während das Hinzufügen Vektoren linear geschieht), aber einen Schwimmer [] auf sie überlagern wie das ist völlig in Ordnung, und ein gut akzeptiertes Mittel von Daten mit GL / DirectX / etc Vertauschung.

Ich empfehle Sie, das von verschiedenen Aliasnamen in der gleichen Funktionsumfang auf das gleiche Element vermeiden Bezug genommen wird, obwohl, weil diese Dich in einen bösen Hardware-Stall treiben wird ein Last-Hit-Speicher genannt. Insbesondere vermeiden dies, wenn Sie können:

vector foo; 
foo.x = 1.0f;
return foo[0] + foo[1];

Referenzen?

template<typename T>
struct vertex {
    vertex() :
        r(data[0]), g(data[1]), b(data[2]),
        x(data[0]), y(data[1]), z(data[2])
    {
    }

    T *operator *() {
        return data;
    }

    const T *operator *() const {
        return data;
    }

    T data[3];
    T &r, &g, &b;
    T &x, &y, &z;
};

Ich denke, man kann einige Makro Magie tun zu bekommen, was Sie wollen. Aber das wird hässlich aussehen. Warum wollen Sie für 3 verschiedene Typen gleiche Struktur, Vertex benutzen? Warum können Sie nicht Klasse für Farbe definieren? Denken Sie auch daran, dass Vertex und Farbe nicht gleich sind. Wenn Sie etwas nach Knoten zu ändern, wirkt sich, dass die Farbe auch, wenn Sie die gleiche Klasse für beide haben.

Ich bin nicht sicher, ob ich die Frage richtig verstanden. Aber es sieht aus wie Sie den Operator [], um eine Überlastung müssen Array bieten wie der Zugriff auf Ihre Struktur / Klasse. Siehe das Beispiel hier erwähnt: Betreiber Überlastung

Nach der Struktur wird das angeforderte Verhalten hat:

struct vertex
{
private:
    float data[3];
public:
    float &x, &y, &z;
    float &r, &g, &b;

    vertex() : x(data[0]), y(data[1]), z(data[2]), r(data[0]), g(data[1]), b(data[2]) {
    }

    float& operator [](int i) { 
        return data[i];
    }
};

Schlechte Idee meiner Meinung nach, zumindest für das Beispiel gegeben: Der Nachteil ist, dass, für fast jede Lösung dieses Problem, sind Sie wahrscheinlich in der Lage sein werden frei „rgb“ Instanzen zu / von „xyz“ zuweisen Instanzen, die wahrscheinlich selten sinnvoll oder richtig ist. dh Sie riskieren einige nützliche Art Sicherheit aufzugeben.

persönlich für das Beispiel, das Sie geben, würde ich rgb und xyz-Typen von einer Basis boost::array<float,3> oder ähnlichen Unterklasse. Also beide erben Operator [] kann an Funktionen übergeben wird Arrays erwartet, und mit mehr Typsicherheit zu vergangenen Farben / Koordinaten erwartet. Es wird oft wollen Sie ein xyz oder ein rgb als Array behandeln, aber selten wollen Sie ein xyz als rgb oder umgekehrt zu behandeln. (Rgb IS-A-Array: OK. Xyz IS-A-Array:.! OK rgb IS-A xyz ???? Ich glaube nicht)

Natürlich, den Zugriff auf x, y, bedeutet, Z & r, g, b muss durch Accessor sein (an den entsprechenden operator[](...) Forwarding), anstatt direkt an das Element. (Sie bräuchten C # 's Eigenschaften für diese).

Ich habe eine Vorlage und zwei Vector Klassen unten, ein verrückte, ein sane. Die Vorlage implementiert eine einfache bei der Kompilierung Array von Werten festgelegt. Es ist für die Unterklassen entwickelt und verwendet eine geschützte Array-Variablen vermeiden Sie durch Reifen zu springen, mit dem Array zuzugreifen. (Einige Leute könnten nicht wie eine solche Konstruktion. Ich sage, wenn Ihr Subklassen Ihre überladenen Operatoren aufrufen, Kopplung eine gute Idee sein könnte.)

Die verrückte Klasse können Sie Membervariablen namens x, y, z haben und es wirkt wie ein Array für Anrufe in glGetFloatV. SANE man hat nur Accessorfunktionen x (), y (), z () und arbeitet immer noch mit glGetFloatV. Sie können entweder Klasse als Basis für andere Vektorobjekte verwenden Sie die OpenGL-Bibliothek passieren könnte. Obwohl die folgenden Klassen spezifisch Punkte sind, können Sie natürlich einfach eine Suchen / Ersetzen sie in RGB Farbklassen zu machen.

Die verrückte Klasse ist verrückt, weil die Kosten für den syntaktischen Zucker vec.x statt vec.x () 3 Referenzvariablen. Das könnte viel Platz in einer großen Anwendung in Anspruch nehmen. Verwenden Sie die einfachere sane Version.

template <typename T, int N>
class FixedVector {
protected:
    T arr[N];
public:
    FixedVector();

    FixedVector(const T* a) {
        for (int i = 0; i < N; ++i) {
            arr[i] = a[i];
        }
    }

    FixedVector(const T& other) {
        for (int i = 0; i < N; ++i) {
            arr[i] = other.arr[i];
        }
    }

    FixedVector& operator=(const T& other) {
        for (int i = 0; i < N; ++i) {
            arr[i] = other.arr[i];
        }
        return *this;
    }

    T* operator&() { return arr; }
    const T* operator&() const { return arr; }

    T& operator[](int ofs) { 
        assert(ofs >= 0 && ofs < N);
        return arr[ofs];
    }
    const T& operator[](int ofs) const { 
        assert(ofs >= 0 && ofs < N);
        return arr[ofs];
    }
};

class CrazyPoint :  public FixedVector<float, 3> {
public:
    float &x, &y, &z;

    CrazyPoint()
      : x(arr[0]), y(arr[1]), z(arr[2])
    { arr[0] = arr[1] = arr[2] = 0.0; }

    CrazyPoint(const float* a)
      : x(arr[0]), y(arr[1]), z(arr[2])
    {
        arr[0] = a[0];
        arr[1] = a[1];
        arr[2] = a[2];
    }

    CrazyPoint(float a, float b, float c) 
      : x(a), y(b), z(c)
    {
        arr[0] = a;
        arr[1] = b;
        arr[2] = c;
    }
};

class SanePoint : public FixedVector<float, 3> {
public:
    float& x() { return arr[0]; }
    float& y() { return arr[1]; }
    float& z() { return arr[2]; }

    SanePoint() { arr[0] = arr[1] = arr[2] = 0.0; }
    SanePoint(float a, float b, float c) 
    {
        arr[0] = a;
        arr[1] = b;
        arr[2] = c;
    }
};

// usage
SanePoint normal;
glGetFloatV(GL_CURRENT_NORMAL, &normal);

Sie können versuchen, Verweise auf Variablen hinzufügen, wie folgt aus:

struct test {
        float x, y, z;
        float &r, &g, &b;

        test() : r(x), g(y), b(z) {}
    };

Aber Ihre Struktur wird größer (von 12 Bytes bis 40 Bytes).

So verwenden Sie [] auf sich, verwendet Überlastung des Operators [], wie zuvor erwähnt.

Nur eine Warnung über Referenzelemente mit an Werten Mitglieder zeigen. Sie benötigen einen Copy-Konstruktor (und möglicherweise auch Zuweisungsoperator) definieren, wenn Sie jemals ein solches Objekt (wie übertragen nach Wert) kopieren. Der Standard Copykonstruktor wird Sie mit einer Kopie, deren Referenzelemente an den Wert Mitglieder des ursprünglichen Objekt zeigen, nicht die des neuen Objekts. Dies ist sicherlich nicht etwas, was Sie wollen.

In Anbetracht Sie auch mit größeren Objekten am Ende, wie bereits erwähnt, ich glaube, mit Accessormethoden bevorzugt über Referenzelemente werden soll.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top