2

I want to implement multi-dimensional array using single array or vector, which can be accessed like usual multi-dimensional array(ex: a[1][2][3]). Where I am stuck at is how to implement [ ] operator. If the dimension of an array is 1, then a[1] should return the element which is located at index 1. But what if the dimension is more than one? In case of nested vector,say 3-dimensinal vector, vec[1] will return vector<vector<some type> >.

The reason why I am trying to implement my own multi-dimensional array is that I don't know the dimension of an array at compile time. The dimension really depends on some conditions. Actually maximum dimension of an array is 3, so I can define three different vectors, but I personally don't think this is the right choice.

0

4 Answers 4

2

operator[] can only take a single argument.

The best solution is to use operator() instead.

If you absolutely want to use operator[] then you can let it return a proxy object, of a type specific to the dimension, on which operator[] can be applied again, and so on.


This is a Frequently Asked Question, and is answered in the C++ FAQ’s “How do I create a subscript operator for a Matrix class?” (the link is to main English version of the FAQ).

It's often a good idea to consult the FAQ before asking.


Sign up to request clarification or add additional context in comments.

3 Comments

elaborate the proxy object plz.
@rupesh.yadav: I'd rather not, sorry. I've done that before, many times, but there are umpteen variations, it's a heck of a lot of code and explanations. Suffice it to say that in general it's inefficient and somewhat brittle, so the only advantage is the more familiar usage notation.
@Cheersandhth.-Alf I should have searched more thoroughly on the Internet before asking. I will consider using operator() instead.
0

You can make an array of vectors

#include<string>
#include<vetor>
using namespace std;
int main()
{
  vector<int> a;
  vector<vector<int> >b; // must have space > >
  vector< vector < vector<int> > > c;
  a.push_back(20);
  a.push_back(10);
  b.push_back(a);
  c.push_back(b);

  int x = c[0][0][0];
  int y = c[0][0][1];
  cout<< y << "  "<< x <<endl;
  return 0;
}

2 Comments

Re the "must have space" comment, that was so in C++03, but no longer in C++11 and C++14.
Can you illustrate how you envision this approach used with number of dimensions known only at run time, not at compile time? It's not impossible but AFAIK the code would be horrendous.
0

The type of any expression must be known at compile-time. a[1][2][3] must have a particular type. It's not possible for the type to vary between int and vector<int> depending on a run-time input.

It is certainly posssible to have a[1][2][3] do something , but this will have to return an object of a given type whose properties you query at runtime to see what happened. (For example, an array with runtime dimension of 1; or throw an exception if too many dimensions are requested).

As others have noted, experience shows that it's less coding and also more effective at runtime to take all dimensions in a single call a(1, 2, 3). If you use operator[] then remembering that operators are function calls, what's going on is a.operator[](1).operator[](2).operator[](3), the extra function calls may make it harder for your compiler to optimize.

Another option is to have the parameters be passed in a container such as a vector, i.e. the user would call a( vec ); where vec is a vector containing the coordinates.

11 Comments

Although I don't know the dimension of the array at compile time,but I do know that the dimension is between 1 and 3. So I can still use [] operator.
@cheers and hth: I really don't see how writing something like a[1][4][2] makes any sense, if I don't even know if a has three dimensions.
@MikeMB: If you don't know the dimensions at all, then writing anything is mostly meaningless, yes. But that's very far from the case of not knowing the dimensions at compile time. There are a lot of multidimensional array classes around with dimensions known only at run time.
@MattMcNabb: first you misrepresent and now you spout rubbish. jeez. even if you are totally unfamiliar with the subject area you should be able to apply logic: this is trivial stuff. but to non-technical readers: if you are a non-technical reader, one of those Matt is writing his comments for, take a look at e.g. the opencv library.
@MattMcNabb: when you assert that it's not helpful to state what's wrong with your answer, you're whining. that's ungood. stop whining, please. all it does is add noise. please do stop making so much noise about it. you were wrong. that's it, no need get all huffy and puffy about it.
|
0

Hi I wrote this multidimensional matrix library (its not full fledged) it supports basic operations like dotproduct and pointwise elements.

https://github.com/josephjaspers/BlackCat_Tensors

Tensor<float> tensor3 = {3, 4, 5};   -- generates a 3 dimensional tensor
tensor3[1] = 3;                      -- returns the second matrix and sets all the values to 3. 
tensor3[1][2];                       -- returns the second matrx and then then 3rd column of that matrix
tensor3({1,2,3},{2,2});              -- at index 1,2,3, returns a sub-matrix of dimensions 2x2

All of the accessor operators [] (int index) and ({initializer_list<int> index},{initializer_list<int> shape}) return seperate tensors but they all refer to the same internal array. Therefor you can modify the original tensor from these sub_tensors.

All the data is allocated on a single array. If you want to use dotproduct you need to link it to BLAS. Here's the header file, it details most of the methods. https://github.com/josephjaspers/BlackCat_Tensors/blob/master/BC_Headers/Tensor.h


In the comments you wanted to elaborate upon accessing using proxy objects

Matrix/Vector

template<typename T>
struct Vector {
 T* data; int sz; 

 Vector<T>(T* data, int size){ 
        this->data = data; 
        this->sz = size; 
 } 
 T& operator[] (int index) { return data[i]; }
}

template<typename T>
struct Matrix {
int row; int col;

 //insert constructor here

 Vector<T> operator[] (int index) {
     return Vector<T>(data[index * row], row); //use col for col-major
 }

}

//Recursive method

template class T
class Tensor {
int* shape;
T* data;

    Tensor<T>(int*shape, int order, T* data){
       this->shape = shape;
       this->order = order;
       this->data  = data; 
    }

    Tensor<T> operator [] (int index) {
      return Tensor(shape, order -1, &data[index * shape[order - 2]); // if the order = 2(tensor is a matrix) multiply the `data` index by given param * the number of rows --> ergo returns a column vector)
    }
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.