Перегрузка оператора [] в переполнении стека многомерных массивов

Когда я звоню: a7 [0] [1] [100];

Я могу получить первый индекс ‘0’ в операторе [], но как индекс я не смогу получить другие значения индекса 1 и 100 так же рекурсивно. Как я мог использовать оператор [], чтобы получить рекурсивные следующие значения индекса. В этом примере для трехмерного массива оператор [] вызывается только один раз для первого измерения, которое равно ‘0’.

Мой пример кода:

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

5

Решение

Ошибка здесь на самом деле немного неуловима, измените строку

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

в

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

Причина этого в том, что array<int, 1, 2, 3>::type равняется array<int, 2, 3>::type что равно array<int, 3>::type который int, В конце концов, вы в конечном итоге array<int, 1, 2, 3>::OneDimensionDownArrayT равно int[2][3], Вот почему вы опускались только на один уровень в вашем перегруженном операторе [], потому что он возвращает фактический массив целых чисел.
Вы можете убедиться в этом сами, добавив в свой основной метод:

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

вместо того, чтобы получить доступ ко всем сразу. Затем перейдите к отладчику и проверьте типы e1-e4. e1 будет иметь тип int (&) [2][3] вместо array<int, 2, 3> &,

Чтобы разместить их в куче, а не в стеке, в вашем классе объявите указатели на OneDimensionDownArrayT вместо их массивов определите конструкторы и дескриптор, который позаботится о распределении / освобождении ваших массивов. Это может выглядеть примерно так:

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

Вы также захотите определить конструктор копирования, конструктор перемещения и оператор присваивания для вашего класса. Эта реализация займет намного меньше места в стеке, но в целом будет занимать чуть больше памяти, так как вам также потребуется место для указателей и самих массивов.

1

Другие решения

Если вы хотите использовать [] операторы подряд многомерный массив, то каждый [] должен вернуть (на один меньше) -мерный массив.

Если ваш тип многомерного массива:

template <class Type, int dim> MArray;

Затем MArray<SomeType, n>::operator[] должен вернуть MArray<SomeType, n-1>, С особым случаем либо для вашего специального 1-D массива, возвращающего объект (предпочтительно ссылка), либо для 2-D массива, возвращающего собственный 1-D массив. В этом примере использовались чрезмерно упрощенные обозначения, но ключ в том, что n-D [] -оператор возвращает (n-1) -D массив.

1

По вопросам рекламы [email protected]