Чтобы прочитать и сохранить некоторые результаты из программы MATLAB, мне нужно использовать до 6-мерных матриц. Вместо того, чтобы делать что-то вроде:
typedef std::vector<double> Row;
typedef std::vector<Row> Matrix2;
typedef std::vector<Matrix2> Matrix3;
typedef std::vector<Matrix3> Matrix4;
typedef std::vector<Matrix4> Matrix5;
typedef std::vector<Matrix5> Matrix6;
Я решил использовать шаблоны, и вот что у меня есть на данный момент:
template <class T, int N>
class Matrix {
public:
typedef typename Matrix<T, N - 1>::type MatrixOneDimLower;
typedef std::vector<MatrixOneDimLower> type;
type _data;
template <unsigned int dn, typename ...NT>
Matrix(unsigned int dn, NT ...drest) : _data(dn, MatrixOneDimLower(drest)) {}
MatrixOneDimLower& operator[](unsigned int index)
{
return _data[index];
}
};
template <class T>
class Matrix<T, 1> {
public:
typedef std::vector<T> type;
type _data;
Matrix(unsigned int d0) : _data(d0, T(0.0)) {}
T& operator[](unsigned int index)
{
return _data[index];
}
};
К сожалению, я не очень разбираюсь в вариативных и рекурсивных шаблонах, и это не работает. Например, если я попытаюсь использовать это как:
Matrix<double, 4> temp(n, dim[2], dim[1], dim[0]);
Я получаю эту ошибку времени компиляции (Visual Studio 2017):
error C2661: 'Matrix<double,4>::Matrix': no overloaded function takes 4 arguments
Буду очень признателен, если вы дадите мне знать, что я делаю не так.
Я думаю, что правильный термин - «тензор шестого порядка».





template<class T, std::size_t I>
struct MatrixView {
MatrixView<T, I-1> operator[](std::size_t i) {
return {ptr + i* *strides, strides+1};
}
MatrixView( T* p, std::size_t const* stride ):ptr(p), strides(stride) {}
private:
T* ptr = 0;
std::size_t const* strides = 0;
};
template<class T>
struct MatrixView<T, 1> {
T& operator[](std::size_t i) {
return ptr[i];
}
MatrixView( T* p, std::size_t const* stride ):ptr(p) {}
private:
T* ptr = 0;
};
template<class T, std::size_t N>
struct Matrix {
Matrix( std::array<std::size_t, N> sizes ) {
std::size_t accumulated = 1;
for (std::size_t i = 1; i < sizes.size(); ++i) {
accumulated *= sizes[N-i];
strides[N-i] = accumulated;
}
storage.resize( strides[0] * sizes[0] );
}
MatrixView<T, N> get() { return {storage.data(), strides.data()}; }
MatrixView<T const, N> get() const { return {storage.data(), strides.data()}; }
private:
std::vector<T> storage;
std::array<std::size_t, N-1> strides;
};
это требует выполнения Matrix<int, 6> m{ {5,4,2,1,3,5} }; для создания матрицы с 6 измерениями.
Для доступа к нему нужно сделать m.get()[3][0][0][0][0][0] = 4.
Вы избавитесь от этого .get(), но это немного раздражает, если вы хотите поддерживать тензоры первого порядка.
Данные хранятся непрерывно.
Большое спасибо! Это очень полезно. Однако у меня есть вопрос, как я могу изменить это, чтобы шаги не были константами времени компиляции. Потому что я не знаю шагов для каждого измерения, пока не загружу файлы. Итак, я хочу иметь возможность писать Matrix<int, 2> a { {d0, d1} }, где d0 и d1 - переменные времени выполнения.
@triple_r Размеры - это просто значения в std::array. Успехи - продукт размеров. На 1 шаг меньше, чем размер, так как измерение верхнего уровня имеет значение только для размера буфера, а не для расстояния между элементами.
Ой, извините, я имел ввиду размер габаритов. Мне нужно было преобразовать свои переменные в size_t, иначе я получал ошибку :-) Еще раз спасибо.
Вам действительно не нужно много вложенных векторов. См. Нижнюю половину моего ответа здесь, чтобы узнать, почему, и игрушечный пример того, как обойти проблему.