简体   繁体   中英

Dynamically allocated multidimensional array using recursive templates

In order to read and store some results from a MATLAB program, I need to use up to 6 dimensional matrices. Instead of doing something like:

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;

I decided to go with templates, and here's what I have so far:

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

Unfortunately, I'm not very adept in variadic templates and recursive templates, and this doesn't work. For example, if I try to use this as:

Matrix<double, 4> temp(n,  dim[2], dim[1], dim[0]);

I get this compile time error (Visual Studio 2017):

error C2661: 'Matrix<double,4>::Matrix': no overloaded function takes 4 arguments

I would really appreciate if you can let me know what I'm doing wrong.

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

this requires doing Matrix<int, 6> m{ {5,4,2,1,3,5} }; to create a matrix with 6 dimensions.

To access it you need to do m.get()[3][0][0][0][0][0] = 4 .

You get get rid of that .get() but it is a bit annoying so long as you want to support tensors of first order.

The data is stored contiguously.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM