В 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 немного исчезает, тем более что мне нужно будет также очистить массив-оболочку.
Другим решением может быть перегрузка оператора шаблонного индекса, где аргументы шаблона содержат первое измерение данных:
Но, как показывают ошибки компиляции, это невозможно без упаковки данных в структуру класса. Итак, обречен ли я обернуть данные в классе и написать много стандартного кода, если я хочу то, что хочу? Пожалуйста, дайте мне знать, что вы думаете!
Если вы используете простой массив, это довольно легко, используя 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
Самый чистый способ сделать это — обернуть плоский массив в классе. Вы можете реализовать использование operator[]
вернуть указатель на Iго строка. Реализация этого operator[]
Нужно знать форму, которую вы хотите наложить на базовый массив.