【发布时间】:2017-12-02 09:26:51
【问题描述】:
我喜欢 C++ 中的范围 for 循环,并希望像这样使用它:
#include <bits/stdc++.h>
int main()
{
for (auto s : LineReader("my-very-big-textfile.txt")) {
cout << s << endl;
}
return 0;
}
这里的目的是遍历一些数据(不先将所有数据读入容器)。在这种情况下,文本字符串是文本文件中的行。但通常它可以是任何东西(包括生成的数据)。
这里 LineReader 返回一个可迭代的“伪”容器。为了让它工作,for 循环需要 LineReader 对象的迭代器。在 C++ 中,范围是根据开始和结束迭代器定义的。但是我想使用范围 for 循环来遍历开始时可能不知道结尾的数据(例如,在(过大的)文本文件中逐行读取而不先通过它来找到结尾。)。
所以我这样定义:
免责声明:显示原理的示例代码,因此我不会通过过度使用 std::、错误处理、私有/公共关键字等来“纠缠”它...
struct ReadLineIterator {
ifstream ifs;
string line;
ReadLineIterator() { }
ReadLineIterator(string filename) : ifs(filename) { }
bool operator!=(ReadLineIterator& other) {
return !ifs.eof();
}
ReadLineIterator& operator++() {
getline(ifs, line, '\n');
return *this;
}
string operator*() {
return line;
}
};
struct LineReader
{
string filename;
LineReader(const string& filename) : filename(filename) { }
ReadLineIterator begin()
{
return ReadLineIterator(filename);
}
ReadLineIterator end() // return a not used dummy iterator since this method must exist
{
return ReadLineIterator();
}
};
当我运行它时,它可以工作。但我怀疑
bool operator!=(ReadLineIterator& other) {
return !ifs.eof();
}
是使此运算符检测序列结尾的正确方法。这是因为我没有任何适当的结束对象(end() 方法只返回一个虚拟迭代器)并且也没有针对它进行比较。相反,我检查流是否为空。
但我不明白我怎么能以其他方式做到这一点?现在我对这种方式很满意,因为它对我有用,但很高兴知道是否有更好的方式来做同样的事情。此外,很高兴知道这是否适用于所有(C++)编译器(我正在使用 GCC),以及它是否适用于未来可能以不同方式处理迭代器的 C++ 标准。
【问题讨论】:
-
当我阅读您的问题的其余部分时,让我开始说,永远不要包含
bits/文件:它们是非标准且不可移植的。改为包含所需的标准标题。 -
不,这不是实现迭代器的正确方法,因为
it != it通常会返回true。 -
那不是一个有效的迭代器。您必须拥有 typedef 和一些其他运算符。此外,正如您所注意到的,
operator!=不会检查other迭代器。请参阅here 了解如何制作合适的迭代器。看起来你想要一个input_iterator。 -
必读:
std::istream_iterator。特别是:“默认构造的std::istream_iterator被称为流尾迭代器。当一个有效的std::istream_iterator到达底层流的末尾时,它就等于流尾迭代器。”跨度> -
@AlexanderHuszagh 恐怕这实际上在 C++17 中已被弃用。参见例如 stackoverflow.com/questions/37031805/… 或 stackoverflow.com/questions/43268146/…
标签: c++ c++11 for-loop iterator operator-overloading