【发布时间】:2014-04-24 04:15:08
【问题描述】:
我正在创建一个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 通过Begin() 和End() 等方法返回std::vector<T>::iterator 迭代器。
我的想法是让RowProxy 知道行的开头和行的大小(矩阵列数)。
问题是RowProxy如何保持行引用的开头:
我的第一个方法是将行首设为
std::vector<T>::iterator。
问题在于,在 Visual Studio 中,迭代器知道向量,并且对迭代器算术进行了调试检查。它在构造ReverseEnd迭代器时抛出错误(对于第一行之前的行):行的开头是num_columns在vector开始之前。 请注意,这与取消引用无关(即 UB)。我无法创建迭代器。。-
我的第二种方法是将行首设为原始指针
T *
这里的问题是LineProxy需要返回std::vector<T>::iterator(通过它自己的Begin等),而我不能(不知道如何)以标准方式从T *构造std::vector<T>::iterator。 (没有找到任何特定于std::vector<T>::iterator的参考,只有迭代器概念。在Visual Studio 中似乎有一个构造函数(T *, std::vector<T> *),在gcc 中是(T *),两者都不能在另一个编译器中工作)。
我现在看到的解决方案是使我自己的迭代器与std::vector<T>::iterator 相同,但没有绑定到任何vector 并且可以从T * 构造并让RowProxy 返回它。但这似乎真的是在重新发明轮子。
由于这是库的一部分(并且代码位于标头中),因此编译器选项是不可能的(包括控制编译器选项的宏,因为它们会修改包含标头的程序的整个行为,而不仅仅是库代码的行为)。此外,解决方案必须符合标准。语言是C++11。
【问题讨论】:
-
当您可以简单地使用Eigen 时,为什么要实现自己的矩阵类。他们很久以前就解决了这一切:)
-
@Wilbert 自学练习,我打算在任务分配中使用我自己的实现。
-
我不明白您建议的
for循环语法如何方便或高效。无论如何,由于没有标准迭代器具有您的Matrix<T>::Iterator<row_double>的行为,您应该自己设计它。我建议您查看std::valarray 的迭代器以获取想法。另请查看std::slice。 -
Matrix<T>::Iterator<row_double>已实现。RowProxy返回的嵌套迭代器现在只是std::vector<T>::iterator
标签: c++ c++11 vector matrix iterator