6

I'm learning C++, so please be patient with me. I have a std::valarray in which there are double elements and I consider it as a 2D matrix.

class Matrix {
    valarray<double> elems;
    int r, c;
public:
/* type? operator[](int r) { return ? } */
//...
}

I want to overload the operator[], so that I can get a row of the matrix, and after that, I want have the m[r][c] access operator.

Is there any way to get a row, as a sequence of double using std::slice in the valarray, so that if I change a value, it is changed also in the matrix?

I've read this definition in valarray:

std::slice_array<T> operator[]( std::slice slicearr );

My operator[] must have std::slice_array<double>& as returned type?

Thanks.

Swordfish
  • 12,971
  • 3
  • 21
  • 43
Sam
  • 263
  • 2
  • 12

1 Answers1

3

I don't think std::slice and std::slice_array is what you're looking for, especially the latter is nothing but a helper type with a very limited public interface. You can instead return an proxy object. Here's a possible example of how to implement that.

class Matrix {
    /* ... */

    class RowProxy {
       public:
          RowProxy(std::valarray<double>& elems, int c, int row) :
              elems(elems), c(c), row(row) {}

          double& operator[](int j)
          {
             return elems[row*c + j];
          }

       private:
          std::valarray<double>& elems;
          int row;
          int c;
    };

    RowProxy operator[](int i)
    {
       return RowProxy(elems, c, i);
    }
};

This way, you can access the data with two operator[].

Matrix m(2, 4); // Assuming the ctor initializes elemens with row*column

m[0][0] = 1.234;
m[1][0] = 2.234;
m[1][3] = -52.023;

Note that both Matrix and RowProxy are missing overloads and proper handling for const-ness, and variable names are poor. Also, you might want to think about an out-of-bounds error handling strategy. But it may serve as a starting point for your implementation.

lubgr
  • 37,368
  • 3
  • 66
  • 117
  • ok, thanks! In this way I can access the element with m[r][c]. I would ask you, if I want to return an object like a Matrix_row() that contain the "reference" to elements in Matrix object, with the syntax m[], how can I do? Is it possible? – Sam Nov 19 '18 at 17:08
  • 1
    @Sam This is exactly the proxy object. You can use it like this: `auto row = m[0]`. Then, index the row as `row[0]`. This is exactly the same as `m[0][0]`. – lubgr Nov 19 '18 at 19:13
  • oooh now I got it, thanks!! Just a question. You speak about error handling strategy, It's a good practise to use the valarray exception in constructor without checking size? I mean, in the constructor I pass int r, int c and I create a valarray with r * c elements, but if r * c is < 0 valarray throw an exception. It's a good practise to use that exception or it is better that I check size before create valarray? – Sam Nov 20 '18 at 10:44
  • 1
    @Sam I think it's fine to do that. Should ideally be documented somewhere. Note, that there is another error that might occur: accessing the array with an out-of-bounds index. This is quite common, you can have a look how `std::vector` handles that - there are two functions, [`std::vector::at`](https://en.cppreference.com/w/cpp/container/vector/at), which throws on out-of-bounds, and [`std::vector::operator[]`](https://en.cppreference.com/w/cpp/container/vector/operator_at) which result in UB when called with an out-of-bounds index. – lubgr Nov 21 '18 at 19:46