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
RowProxymember - 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 theReverseEnditerator (for the line before the first line): the beginning of the line isnum_columnsbefore thevectorstart. 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 thatLineProxyneeds to returnstd::vector<T>::iterator(via it's ownBeginetc.) and I cannot (don't know how to) construct astd::vector<T>::iteratorfrom aT *in a standard way. (Didn't find any reference specific tostd::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.