5

Wenn ich rufe: a7 [0] [1] [100];Operator [] Überladen in mehrdimensionalen Arrays C++

Ich bin in der Lage, den ersten Index '0' im Operator [] zu erhalten, aber als Index kann ich nicht andere Indexwerte 1 und 100 rekursiv erhalten. Wie könnte ich den Operator [] verwenden, um rekursive folgende Indexwerte zu erhalten. In diesem Beispiel für das 3-dimensionale Array wird operator [] nur einmal für die erste Dimension aufgerufen, die "0" ist.

Mein Beispielcode:

template <class T, unsigned ... RestD> struct array; 

template <class T, unsigned PrimaryD> 
struct array <T, PrimaryD> { 
    typedef T type[PrimaryD]; 

    type data; 

    T& operator[] (unsigned i) { 
     return data[i]; 
    } 
}; 

template <class T, unsigned PrimaryD, unsigned ... RestD> 
struct array <T, PrimaryD, RestD...> { 
    typedef typename array<T, RestD...>::type OneDimensionDownArrayT; 
    typedef OneDimensionDownArrayT type[PrimaryD]; 

    type data; 

    OneDimensionDownArrayT& operator[] (int i) { 
     OneDimensionDownArrayT& a = data[i]; 
     return a; 
    } 
}; 

int main() { 

    array<int, 1, 2, 3> a7 {{{{1, 2, 3},{4, 5, 6}}}}; 
    a7[0][1][2] = 100; //=>won't recursively go through operator[] 
        //I want to recursively obtain 0, 1 and 2 as index values 

    a7[0][1][100] = 100; //also works correctly. 
    std::cout << a7[0][1][100] << std::endl; 

    return 0; 
} 
+0

Also, was ist das Problem? Welches Verhalten siehst du? Wenn es einen Kompilierungsfehler gibt, was ist es? Was ist das Laufzeitverhalten? Was ist dein Compiler und deine Version? Ein bisschen mehr Information tut nicht weh, weißt du! – yzt

+3

Haben Sie überlegt, ob Sie das nicht tun? Verwenden Sie stattdessen einfach eine 'operator()' Überladung. Wirklich, Leute versuchen * way * zu schwer, 'operator []' in mehrdimensionale Arrays zu beschatten. –

+5

Ein paar Randnotizen: [Warum sollte die Schnittstelle meiner Matrix-Klasse nicht wie ein Array-Array aussehen?] (Http://www.parashift.com/c++faq/matrix-array-of-array).html) und [ich verstehe es immer noch nicht. Warum sollte die Benutzeroberfläche meiner Matrix-Klasse nicht wie ein Array-Array aussehen? (Http://www.parashift.com/c++faq/matrix-c-style-subscripts.html) –

Antwort

1

Die hier Fehler ist eigentlich ein wenig subtil, die

typedef typename array<T, RestD...>::type OneDimensionDownArrayT; 

zu

typedef array<T, RestD...> OneDimensionDownArrayT; 

Der Grund für diese Linie ändern ist, weil array<int, 1, 2, 3>::type equals array<int, 2, 3>::type was gleich array<int, 3>::type ist, was 01 ist. Am Ende enden Sie mit array<int, 1, 2, 3>::OneDimensionDownArrayT gleich int[2][3]. Aus diesem Grund sind Sie in Ihrem überladenen Operator [] nur eine Ebene tiefer gegangen, weil sie ein tatsächliches Array von Ints zurückgibt. Sie können selbst sehen dies in der Hauptmethode hinzu:

 auto & e1 = a7[0]; 
     auto & e2 = e1[0]; 
     auto & e3 = e2[1]; 
     auto & e4 = e3[2]; 
     e4 = 100; 

anstatt sie alle auf einmal zuzugreifen. Dann gehen Sie mit dem Debugger durch und prüfen Sie die Typen von e1-e4. e1 hat den Typ int (&) [2][3] anstelle von array<int, 2, 3> &.

Um diese auf dem Heap statt auf dem Stack zuzuweisen, deklarieren Sie in Ihrer Klasse Zeiger auf Ihre OneDimensionDownArrayT anstelle von Arrays von ihnen, Konstruktoren und einen Destruktor, der für die Zuweisung/Freigabe ihrer Arrays sorgen wird. Es könnte wie folgt aussehen:

template <class T, unsigned PrimaryD, unsigned ... RestD> 
    struct array <T, PrimaryD, RestD...> { 
     typedef typename array<T, RestD...>::type OneDimensionDownArrayT; 

     array():data(new OneDimensionDownArrayT[PrimaryD]){} 
     ~array() { 
      delete[] data; 
     } 

     OneDimensionDownArrayT * data; 

     OneDimensionDownArrayT& operator[] (int i) { 
      OneDimensionDownArrayT& a = data[i]; 
      return a; 
     } 
    }; 

Sie werden auch einen Kopierkonstruktor definieren wollen, Konstruktor und Zuweisungsoperator für die Klasse bewegen. Diese Implementierung benötigt viel weniger Platz auf dem Stack, aber insgesamt etwas mehr Speicher, da Sie auch Platz für die Zeiger und die Arrays selbst benötigen.

+0

Diese Lösung ist ineffizient für sehr große Arrays wie a1 [1] [2] [3] [4] [5] [6] [7] [8] [9] [10]. Da innerhalb jedes Objekts ein anderes Array-Objekt erstellt wird, ist die Speicherbelegung bei einer Dimensionserweiterung sehr groß. – Alper

+0

Egal, was Sie tun, Sie müssen Platz für 10 reservieren! Objekte. Wenn der Speicherplatz auf dem Stapel knapp wird, versuchen Sie, den Heapspeicher zu verwenden (den Speicher dynamisch zuzuweisen). – SirGuy

+0

typedef-Array OneDimensionDownArrayT; funktioniert, aber unter dem Objekt jeder Dimension erzeugt es ein Array-Objekt und es wird unnötiges Gedächtnis verbrauchen. Es gibt mehr als 10 Objekte, weil es ein mehrdimensionales Array ist. Wie könnte ich dynamisch zuordnen => typedef Array OneDimensionDownArrayT; – Alper

1

Wenn Sie []-Operatoren nacheinander und ein mehrdimensionales Array verwenden möchten, muss jedes [] ein (ein weniger) -dimensionales Array zurückgeben.

Wenn Ihr mehrdimensionale Array-Typ ist:

template <class Type, int dim> MArray; 

Dann wird ein MArray<SomeType, n>::operator[] muss eine MArray<SomeType, n-1> zurück. Mit einem speziellen Fall für entweder Ihr spezielles 1-D-Array, das ein Objekt (vorzugsweise eine Referenz) oder ein 2-D-Array zurückgibt, das ein natives 1-D-Array zurückgibt. In diesem Beispiel wurde eine übermäßig vereinfachte Notation verwendet. Der Schlüssel ist jedoch, dass ein n-D [] -Operator ein (n-1) -D-Array zurückgibt.