1

I have created a one dimensional vector of int, how may I treat it like 2 dimensional one?

While I can write arr[1]; I can't write arr[1][2];

Why I need this: Instead of defining a vector of vectors [3x5] I defined a vector whose length is 15, so every time I have a function that takes coordinations of a place in matrix I have to call another function which converts those into one dimensional value, which is really annoying.

  • I'm not sure what you mean. Why do you want to access a 1D vector like it's 2D? – cigien Jun 26 '20 at 17:33
  • yes exactly @cigien –  Jun 26 '20 at 17:33
  • because I was supposed to define it as a matrix but for efficiency I used one dimensional vector –  Jun 26 '20 at 17:34
  • instead of using vector of vectors –  Jun 26 '20 at 17:34
  • Please add all that information to the question, instead of adding it as comments. Also, try to explain what you mean in code, instead of describing it. – cigien Jun 26 '20 at 17:36
  • updated my post @cigien –  Jun 26 '20 at 17:40
  • 1
    It's not gonna be an easy solution, because efficiency sometimes make the coding job harder. You'll have to treat a single dimensional array/vector as two dimensional, only within your algorithm. e.g. in your case, instead of `arr[1][2]`, you'll write `arr[1 * 5 + 2]`. – Coral Kashri Jun 26 '20 at 17:41
  • You can treat a 1D array as N dimensional using addressing, or for 2D: `arr[x + y * w]` Where `w` is the "width" of the `y` dimension. You could use `std::vector>` if you want an actual 2D array. – tadman Jun 26 '20 at 17:45
  • 2
    This isn't (quite) a duplicate question, but the [answer I wrote](https://stackoverflow.com/a/2216055/179910) to a previous question covers this pretty well nonetheless. – Jerry Coffin Jun 26 '20 at 17:51

3 Answers3

2

Assuming you want to treat a 1D array of size N as a 2D array with M columns, then you can write a helper function that computes the 1D index given 2D indexes:

auto in = [M] (int i, int j) { return i * M + j; };

and then use it like this:

arr[in(i,j)];

This is at least preferable to saying arr[i * M + j] everywhere, which is error prone.

Ideally, you would wrap this 1D array into a class that supports 2D indexing.

cigien
  • 57,834
  • 11
  • 73
  • 112
0

It seems to me that the best solution is avoid at all the double operator[] and define an at() function that receive two indexes.

Anyway, if you really (really!) want a double operator[] solution, the first one has to return an object with requested data and support the second operator[]

I propose the following skeletal example, where a arr2d (with compile time known dimension) is based over a mono-dimensional std::array.

#include <array>
#include <iostream>

template <typename T, std::size_t Dim1, std::size_t Dim2>
class Arr2d
 {
   private:
      using int_arr_t = std::array<T, Dim1 * Dim2>;

      int_arr_t  arr{};

   public:
      struct foo
       {
         int_arr_t & arr;

         std::size_t const  i1;

         T & operator[] (std::size_t i2)
          { return arr[i1*Dim1 + i2]; }

         T const & operator[] (std::size_t i2) const
          { return arr[i1*Dim1 + i2]; }
       };

      foo operator[] (std::size_t i1)
       { return {arr, i1}; }

      foo const operator[] (std::size_t i1) const
       { return {arr, i1}; }
 };

int main ()
 {
   Arr2d<int, 2, 3>  a2d;

   a2d[1][2] = 3;

   std::cout << a2d[1][2] << std::endl;
 }

As you can see, the arr2d::operator[] return a foo object containing a reference to the std::array and the first index.

The foo::operator[] complete the job, returning a reference (or a constant reference, according the case) to the right element inside the original std::array.

But, I repepeat: i prefer a couple of at() functions in Arr2d

T & at (std::size_t i1, std::size_t i2)
 { return arr[i1*Dim1 + i2]; }

T const & at (std::size_t i1, std::size_t i2) const
 { return arr[i1*Dim1 + i2]; }
max66
  • 65,235
  • 10
  • 71
  • 111
  • A nested `std::array` could be used instead of `struct foo`. – HolyBlackCat Jun 26 '20 at 19:03
  • 1
    @HolyBlackCat - Do you mean a `std::array, Dim1>`? Yes; and is a simpler and (I suppose) better solution. But I suppose also that the OP want a double `operator[]` over a single array of data. – max66 Jun 26 '20 at 19:07
0

The use of the comma operator was deprecated inside square brackets with C++20. This will in the future enable to write something like m[i, j] for matrix access.

Until then your only chance is to use a member function like at.

A clever and not recommended approach is to have operator[] return some kind of row proxy that has a operator[] on its own to perform the indexing. That is shown here.

Note that storing the row_proxy can lead to dangling pointers which is why operator[]is only implemented for rvalue references.

sv90
  • 522
  • 5
  • 11