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 theReverseEnd
iterator (for the line before the first line): the beginning of the line isnum_columns
before thevector
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 thatLineProxy
needs to returnstd::vector<T>::iterator
(via it's ownBegin
etc.) and I cannot (don't know how to) construct astd::vector<T>::iterator
from 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
.