我正在创建一个Matrix<T>
类。在为其实现迭代器时,我偶然发现了一个设计难题。
在内部,矩阵将数据保存在std::vector<T>
(行优先)中。
遍历矩阵的一种方法是使用双迭代器(嵌套)(由row_double
模板参数指定):
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;
}
第一个迭代器
Matrix<T>::Iterator<row_double>
:遍历矩阵的行
有一个
RowProxy
成员取消引用它会返回一个
RowProxy
。RowProxy
通过std::vector<T>::iterator
和Begin()
之类的方法返回End()
迭代器。我的想法是让
RowProxy
知道行的开头和行的大小(矩阵列的数量)。问题是
RowProxy
如何保存行引用的开头:我的第一种方法是将行的开头设为
std::vector<T>::iterator
。问题在于,在Visual Studio中,迭代器知道矢量,并且存在对迭代器算法的调试检查。构造
ReverseEnd
迭代器时(对于第一行之前的行),它将引发错误:行的开头是num_columns
开始之前的vector
。请注意,这与取消引用无关(Whitch是UB)。我无法创建迭代器。我的第二种方法是使行的开头成为原始指针
T *
这里的问题是
LineProxy
需要返回std::vector<T>::iterator
(通过它自己的Begin
等),而我不能(不知道如何)以标准方式从std::vector<T>::iterator
构造T *
。 (没有找到任何特定于std::vector<T>::iterator
的引用,只是迭代器概念。在Visual Studio中,似乎在gcc和(T *, std::vector<T> *)
中都有构造器(T *)
,而在另一个编译器中都无效。)我现在看到的解决方案是使我自己的迭代器与
std::vector<T>::iterator
相同,但该迭代器不受任何vector
约束,并且可以从T *
构造并让RowProxy
返回。但这似乎真的是在重新发明轮子。由于这是库的一部分(并且代码位于标头中),编译器选项是不可能的(包括控制编译器选项的宏,因为它们会修改包括标头的程序的整个行为,而不仅是修改标头的行为)库代码)。另外,解决方案必须符合标准。语言是
C++11
。 最佳答案
如上所述,最简单的方法是使用Eigen,它确实是一个非常不错的软件包。接下来要做的最简单的事情是将大小信息存储在您的类中,然后您就有了一种很好的方法从矩阵中获取特定元素。只需编写一个(i,j)运算符即可返回vector [i + j * rowlength]。迭代器应该可以很好地在一个循环中循环遍历整个向量,而不知道在两个循环中循环产生多少意义。