I have used this template several times when creating variable-size matrix class class templates.
Matrix.h
#ifndef MATRIX_H template<typename Type, size_t... Dims> class Matrix { public: static const size_t numDims_ = sizeof...(Dims); private: size_t numElements_; std::vector<Type> elements_; std::vector<size_t> strides_; // Technically this vector contains the size of each dimension... (its shape) // actual strides would be the width in memory of each element to that dimension of the container. // A better name for this container would be dimensionSizes_ or shape_ public: Matrix() noexcept; template<typename... Arg> Matrix( Arg&&... as ) noexcept; const Type& operator[]( size_t idx ) const; size_t numElements() const { return elements_.size(); } const std::vector<size_t>& strides() const { return strides_; } const std::vector<Type>& elements() const { return elements_; } }; // matrix #include "Matrix.inl" #endif // MATRIX_H
Matrix.inl
template<typename Type, size_t... Dims> Matrix<Type, Dims...>::Matrix() noexcept : strides_( { Dims... } ) { using std::begin; using std::end; auto mult = std::accumulate( begin( strides_ ), end( strides_ ), 1, std::multiplies<>() ); numElements_ = mult; elements_.resize( numElements_ ); }
Matrix.cpp
#include "Matrix.h" #include <vector> #include <numeric> #include <functional> #include <algorithm>
main.cpp
#include <vector>
This is a simple variable multi-dimensional matrix class. Same Type <T>
You can create a matrix of float, ints, chars, etc. different sizes, such as 2x2 , 2x3 , 5x3x7 , 4x9x8x12x2x19 . This is a very simple but universal class.
It uses std::vector<> , so the search time is linear. The larger the multidimensional matrix grows in size, the larger the inner container will grow depending on the size of each dimension; it can “explode” quite quickly if each individual size has a large size, for example: a 9x9x9 is only 3 dimensional volumetric matrix , which has much more elements than 2x2x2x2x2 , which is 5 dimensional volumetric matrix . The first matrix has elements 729 , where the second matrix has only elements 32 .
I did not enable the default constructor , copy constructor, move constructor, and any overloaded constructors that accept either std::container<T> or another Matrix<T,...> . This can be done as an exercise for the OP.
I also did not include any simple functions that would give the size of common elements from the main container, as well as the number of general sizes that would be the size of the strides container. The OP should be able to implement this very simply.
As for strides and for indexing with multidimensional OP coordinates, it will be necessary to use stride values to calculate the corresponding indices again. I leave this as the main exercise.
EDIT . I went ahead and added a default constructor, moved some members to a private section of the class, and added several access functions. I did this because I just wanted to demonstrate the strength of this class in the main function even when creating an empty container of my type.
Even more, you can answer Yakk with your step and cut algorithm, and you can easily connect it directly to this class, giving you the full functionality of what you are looking for.