5

Kiedy wołam: a7 [0] [1] [100];Operator [] Przeciążanie w wielowymiarowych tablicach C++

Jestem w stanie uzyskać pierwszy indeks "0" w operatorze [], ale jako indeks I nie będę mógł uzyskać innych wartości indeksu 1 i 100 jako rekursywnie. W jaki sposób mogłem użyć operatora [] w celu uzyskania wartości indeksu rekursywnego. W tym przykładzie dla tablicy trójwymiarowej operator [] jest wywoływany tylko raz dla pierwszego wymiaru, który jest "0".

moim przykładzie Kod:

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

Jaki jest problem? Jakie zachowanie widzisz? Jeśli daje błąd kompilacji, co to jest? Jakie jest zachowanie środowiska wykonawczego? Jaki jest twój kompilator i wersja? Trochę więcej informacji nie boli, wiesz! – yzt

+3

Czy brałeś pod uwagę ... nie robisz tego? Zamiast tego użyj przeciążenia 'operator()'. Naprawdę, ludzie próbują * droga * zbyt ciężko, aby wsunąć 'operatora []' w wielowymiarowe tablice. –

+5

Kilka uwag bocznych: [Dlaczego interfejs mojej klasy Matrix nie powinien wyglądać jak tablica tablic?] (Http://www.parashift.com/c++-faq/matrix-array-ofray-array.html) i [wciąż go nie rozumiem. Dlaczego interfejs mojej klasy Matrix nie powinien wyglądać jak tablica tablic?] (Http://www.parashift.com/c++-faq/matrix-c-style-subscript.html) –

Odpowiedz

1

Błąd tutaj jest rzeczywiście mało subtelne, zmienić linię

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

do

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

Powodem tego jest fakt, array<int, 1, 2, 3>::type równi array<int, 2, 3>::type co równa się array<int, 3>::type, czyli int. W końcu kończysz z array<int, 1, 2, 3>::OneDimensionDownArrayT równym int[2][3]. To dlatego obniżyłeś tylko jeden poziom w przeciążonym operatorze [], ponieważ zwraca on rzeczywistą tablicę intów. Można to zobaczyć na własne oczy, dodając w głównym sposobem:

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

zamiast dostępie je wszystkie naraz. Następnie przejdź za pomocą debuggera i sprawdź typy e1-e4. e1 będzie mieć typ int (&) [2][3] zamiast array<int, 2, 3> &.

Aby przeznaczyć je na stercie zamiast na stosie, w klasie zadeklarować wskaźniki do swojej OneDimensionDownArrayT zamiast tablic nich definiować konstruktorów i desctructor że zadba o przydzielenie/dealokując swoich tablic. Może to wyglądać mniej więcej tak:

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

Będziesz także chcą zdefiniować konstruktor kopiujący, przesuń konstruktor i operator przypisania dla swojej klasy. Ta implementacja zajmie znacznie mniej miejsca na stosie, ale ogólnie nieco więcej pamięci, ponieważ potrzebujesz również miejsca na wskaźniki, a także same tablice.

+0

To rozwiązanie jest nieskuteczne w przypadku bardzo dużych macierzy, takich jak a1 [1] [2] [3] [4] [5] [6] [7] [8] [9] [10]. Ponieważ wewnątrz każdego obiektu tworzy on inny obiekt tablicy, który, gdy rozmiar wymiaru zwiększa wykorzystanie pamięci, będzie tak duży. – Alper

+0

Bez względu na to, co robisz, musisz przydzielić miejsce na 10! obiekty. Jeśli brakuje miejsca na stosie, spróbuj użyć sterty (dynamicznie alokując pamięć). – SirGuy

+0

tablica typedef OneDimensionDownArrayT; działa, ale pod obiektem każdego wymiaru tworzy obiekt i szykuje i zużyje pamięć unnessarną. Istnieje ponad 10 obiektów, ponieważ jest to tablica wielowymiarowa. Jak mogę dynamicznie przydzielić => typedef array OneDimensionDownArrayT; – Alper

1

Jeśli chcesz używać kolejno operatorów [] i wielowymiarowej tablicy, to każdy [] musi zwrócić (mniejszą) tablicę wielowymiarową.

Jeśli wielowymiarowa tablica jest typu:

template <class Type, int dim> MArray; 

Następnie MArray<SomeType, n>::operator[] musi zwrócić MArray<SomeType, n-1>. Ze specjalnym przypadkiem dla twojej specjalnej macierzy 1-D zwracającej obiekt (najlepiej referencję) lub tablicę 2-D zwracającą natywną tablicę 1-D. W tym przykładzie zastosowano zbyt uproszczoną notację, ale kluczem jest to, że operator n-D [] zwraca tablicę (n-1) -D.