Designing iterators for a Matrix class

2019-08-05 13:22发布

问题:

I am creating a Matrix<T> class. While implementing iterators for it I stumbled upon a design conundrum.

Internally, the matrix holds the data in a std::vector<T> (row-major).
One way of iterating through the matrix is by double iterators (nested) (specified by the row_double template parameter):

for (auto it_i = mat.Begin<row_double>(); it_i < mat.End<row_double>(); ++it_i) {
  for (auto it_j = it_i->Begin(); it_j < it_i->End(); ++it_j) {
    cout << *it_j << " ";
  }
  cout << endl;    
}

The first iterator Matrix<T>::Iterator<row_double>:

  • iterates through the rows of the matrix
  • has a RowProxy member
  • Dereferencing it returns a RowProxy.

RowProxy returns std::vector<T>::iterator iterators via methods like Begin() and End().

My idea is for the RowProxy to know the beginning of the line and the size of the line (number of matrix columns).

The problem is how RowProxy holds the beginning of the line reference:

  • My first approach was to make the beginning of the line a std::vector<T>::iterator.
    The problem is that in Visual Studio the iterator is aware of the vector and there are debug checks for iterator arithmetics. It throws an error when constructing the ReverseEnd iterator (for the line before the first line): the beginning of the line is num_columns before the vector start. please note that this has nothing to do with dereferencing (whitch is UB). I can't create the iterator..

  • My second approach was to make the beginning of the line a raw pointer T *
    The problem here is that LineProxy needs to return std::vector<T>::iterator (via it's own Begin etc.) and I cannot (don't know how to) construct a std::vector<T>::iterator from a T * in a standard way. (Didn't find any reference specific to std::vector<T>::iterator, just iterator concepts. In visual Studio there seems to be a constructor (T *, std::vector<T> *), in gcc a (T *), neither one works in the other compiler).

The solution that I see now is to make my own iterator identical with std::vector<T>::iterator but who isn't bound to any vector and can be constructed from T * and make RowProxy return that. But this really seems like reinventing the wheel.

Since this is part of a library (and the code resides in headers), compiler options are out of the question (including macros that control compiler options because they modify the whole behaviour of the program that includes the header, not just the behaviour of the library code). Also the solution must be conforming to the standard. The language is C++11.

回答1:

The simplest way to do this as stated above is to use Eigen, it is really a very nice package. The next simplest thing to do would be to store size information in your class then you have a very nice way of getting a specific element out of your matrix. Just write an (i,j) operator that returns vector[i + j*rowlength]. Iterators should work well for looping over the whole vector in one loop, not sure how much sense it makes to loop over in two.