Const Double Indexing with [][] in Matrix Class

2019-08-19 07:09发布

问题:

The following code contains a simple example of a Matrix class, with double indexing [][] enabled using a 'proxy' Row class.

#include <valarray>
#include <iostream>

template <typename T>
class Matrix {

private:

  // Data members
  int nRows_;
  int nColumns_;
  std::valarray<T> data_;

public:

  // Constructor
  Matrix(const int nRows,
         const int nColumns)
    : nRows_{nRows},
      nColumns_{nColumns},
      data_{std::valarray<T>(nRows*nColumns)} {}

  // Row friend class to enable double indexing
  class Row {   
    friend class Matrix;

  private:

    // Constructor
    Row(Matrix& parent,
        int row)
      : parent_{parent},
        row_{row} {}

    // Data members
    Matrix& parent_;
    int row_;

  public:

    // Index columns
    T& operator[](int column) {
      int nColumns{parent_.nColumns_};
      int element{row_*nColumns + column};
      return parent_.data_[element];
    }
  };

  // Index rows
  Row operator[](int row) {
    return Row(*this, row);
  }
};

However, this doesn't allow double indexing of a const Matrix. For example, the below code fails to compile when the last line is included.

int main() {

  Matrix<int> a{3,3};
  const Matrix<int> b{3,3};
  std::cout << a[1][2];
  std::cout << b[1][2];
}

So the question is, how can I modify my Matrix class to allow for double indexing of const Matrix objects?

回答1:

Since b is a const Matrix, you need to add const versions of your indexing operator.

Row operator[](int row) const { ... }

This will require additional changes to the Row class (or a second proxy class) to handle the const Matrix & and const overload of operator[].



回答2:

I think I'm lacking a logical understanding of why things need/need not be const

It depends if you can modify argument or not. in general operator[] should not change object (unless it does, but then...ugh), it should return reference to object's resource. Tada! Your implementation doesn't allow that, because valarray is const then. You cant assign const matrix reference to

 Matrix& parent_;

And as result

 Row(const Matrix& parent, int row)  

Why store Matrix itself... I'd stored reference of valarray.

Actually I would ditch container and create own transparent array in heap. that way Row would have a reference to part of array and length of row, nearly zero of overhead.