Переосмысление Matlab в переполнении стека

В Matlab возможно «преобразовать» (N-мерную) матрицу из любого измерения в любое другое измерение, пока количество элементов не изменится. То есть:

A = rand(10,10);
B = reshape(A, 100, 1);

Matlab может делать это довольно эффективно, поскольку A и B по-прежнему указывают на один и тот же блок из 100 двойных чисел, они копируются только в том случае, если выполняется запись в A или B: это называется копированием при записи.

Я хочу эту функцию изменения формы в C / C ++, то есть я хочу иметь возможность сделать это:

double flat[100];
double square[10][10] = ... flat ...;

такой, что квадрат представляет те же данные, но интерпретирует индексацию по-другому.

В конце я хочу использовать синтаксис Sugar, чтобы сделать квадрат [i] [j] вместо квадрата [10 * i + j]. Итак, да, написание некоторого класса, который может обмениваться данными с различными измерениями (как это делает Matlab), перегружая операторы индексации, может сделать работу. Однако я ищу более простое решение.

С другой стороны, я боюсь, что стандарт (ы) C ++ позволяют компиляторам реализовывать размерные массивы различными способами, что не позволяет того, что я хочу. Например, int [10] [10] может быть реализован как 10 блоков по 10 двойных и один блок из 10 двойных указателей, указывающих на них. Более того, я могу сам создать такую ​​вещь:

double **blowUp(double *array, int m, int n) {
double **r = new double[m];
for(int i=0; i<m; ++i, array+=n) r[i] = array;
return r;
}

но затем идея синтаксиса sugar немного исчезает, тем более что мне нужно будет также очистить массив-оболочку.

Другим решением может быть перегрузка оператора шаблонного индекса, где аргументы шаблона содержат первое измерение данных:

http://ideone.com/aonHN2

Но, как показывают ошибки компиляции, это невозможно без упаковки данных в структуру класса. Итак, обречен ли я обернуть данные в классе и написать много стандартного кода, если я хочу то, что хочу? Пожалуйста, дайте мне знать, что вы думаете!

2

Решение

Если вы используете простой массив, это довольно легко, используя reinterpret_cast, Принимая ваш пример:

#include <iostream>

int main()
{
int flat[100];
for (int i=0; i<100; ++i)
flat[i]=i;
// now reinterpret that flat array as a 10x10 square
int (&square)[10][10] = *reinterpret_cast<int(*)[10][10]>(flat);
// print an arbitrary row
for (int i=0; i<10; ++i)
std::cout << square[5][i] << ' ';
std::cout << '\n';
}

Эта простая программа печатает:

50 51 52 53 54 55 56 57 58 59
4

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

Самый чистый способ сделать это — обернуть плоский массив в классе. Вы можете реализовать использование operator[] вернуть указатель на Iго строка. Реализация этого operator[] Нужно знать форму, которую вы хотите наложить на базовый массив.

2

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