我正在创建一个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>::iteratorBegin()之类的方法返回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]。迭代器应该可以很好地在一个循环中循环遍历整个向量,而不知道在两个循环中循环产生多少意义。

09-30 14:48
查看更多