-1

Let's assume i want to implement a class for n-dimensional Matrix of values of type T:

template <typename T> class Matrix
{
 Matrix(const unsigned &dimensions ); //constructor
 T &operator[](int idx);  //set data operator
 const T &operator[](int idx) const; //get data operator
}

Matrix m(3);
m[0][0][0] = 1;
m[1][2][3] = 4;

How can I write an operator[][] to access data inside n-dimensional Matrix. Eg:

Is there a difference between writing operator of for 2-dimenstional Matrix, 3 etc?

EDIT 1

This question is similar to "Operator[][] overload", but it's about more general case, about n-dimesional Matrixes.

Although the below answer is correct: https://stackoverflow.com/a/11109487/4732868

Community
  • 1
  • 1
  • 4
    duplicate of http://stackoverflow.com/q/6969881/4077900 ? – anukul Apr 05 '16 at 06:06
  • 2
    In reference to the linked question and answer above, your proxy object might need to contain special information such as which dimension is being accessed. Actually, the proxy could be another `Matrix` with a special constructor. This is fairly easy if you implement your matrix storage as a single block of memory. Then you can just flag it as an intermediate object, set the dimensions accordingly, and perform any other matrix operation on it - effectively it becomes a slice. Might not be appropriate for other operations that perform strided slices, but that's not really what you're asking. – paddy Apr 05 '16 at 06:11

2 Answers2

3

You need something like this:

// Matrix.h
#ifndef MATRIX_H
#define MATRIX_H

#include <map>

/**
 * This is the default container class using in Matrix. This can easily
 * be changed through template paramenters of Matrix. See below for more
 * about what the container is used for.
 */
template <typename T>
class DefaultContainer : public std::map<int, T>
{

};

/**
 * Matrix is a class template that implements a multi-dimensional storage
 * of specific type T. The Container is responsible to how these Ts will
 * be stored and retrieved from memory.
 * This is the general case for dimensions > 1. For the simple case of 1
 * dimension see below.
 */
template <typename T,
          int dimensions,
          template <typename> class Container = DefaultContainer
          >
class Matrix
{
    /**
     * A Matrix of n dimensions is actually an array of matrices each has
     * n-1 dimensions.
     * This is what happens here. m_data, in its simple case, is an array
     * of itemTypes each of them is defined as a Matrix of dimensions-1
     */ 
    typedef Matrix<T,dimensions-1, Container> itemType;

    Container<itemType> m_data;

public:
    /**
     * This returns an item of the array m_data which is probably a matrix
     * of less dimensions that can be further accessed be the same operator
     * for resolving another dimension.
     */
    itemType& operator[](int idx)
    {
        return m_data[idx];
    }

    const itemType& operator[](int idx) const
    {
        return m_data[idx];
    }
};

/**
 * This is the simple case of a one-dimensional matrix which is technically
 * an array in its simplest case.
 */
template <typename T,
          template <typename> class Container
          >
class Matrix<T,1,Container>
{
    /**
     * Here we are defining an array of itemType which is defined to be T.
     * so we are actually defining an array of T.
     */
    typedef T itemType;

    Container<itemType> m_data;

public:
    itemType& operator[](int idx)
    {
        return m_data[idx];
    }

    const itemType& operator[](int idx) const
    {
        return m_data[idx];
    }
};

#endif // MATRIX_H

Example Usage:

#include <iostream>
#include "matrix.h"

int main(int argc, char *argv[])
{
    Matrix<int, 2> m;

    /**
     * m here is a two-dimensional matrix.
     * m[0] is resolving the first dimension of the matrix. it is like
     * getting the first row which should be an array of items. And this
     * is actually what m[0] returns. It returns a one-dimensional matrix
     * (an array) whose items can also be accessed using operator[] to
     * get one of those items m[0][1].
     */

    m[0][1] = 1;
    m[1][2] = 5;

    std::cout << m[0][1];
    std::cout << m[1][2];

    return 0;
}
Meena Alfons
  • 1,230
  • 2
  • 13
  • 30
0

I accomplished this in a very round-about way: I made the Matrix a vector of vectors (for 2-d) and overloaded the operator[] to return a vector, and since the vector object has an overload for operator[] it gives the illusion that you're doing what is essentially done in the array (array[int][int]). It would be hard to specify dimensions this way, however. Another option is to just do what is done here (link courtesy of momo) and use the operator()(int, int, int, etc...).

Community
  • 1
  • 1
Zackeezy
  • 74
  • 8
  • Vector of vectors is a pretty gnarly way to implement a matrix, as it scatters your data all over the heap. Every extra dimension you add makes it worse! It might be appropriate in some cases to have a vector at the outer dimension and partition the data into sensible blocks with good cache locality. – paddy Apr 05 '16 at 06:24