C++自定义惰性迭代器
C++ custom lazy iterator
>我有一个比较简单的文本文件解析器。我解析的文本被分成用{ block data }
表示的块。
我的解析器有一个string read()
函数,它可以获取令牌,因此在上面的示例中,第一个令牌{
后跟block
后跟data
后跟}
。
为了减少重复,我想编写一个类似生成器的迭代器,它允许我编写类似于此 JavaScript 代码的内容:
* readBlock() {
this.read(); // {
let token = this.read();
while (token !== '}') {
yield token;
token = this.read();
}
}
这反过来又允许我使用简单的 for-of 语法:
for (let token of parser.readBlock()) {
// block
// data
}
对于C++,我想要类似的东西:
for (string token : reader.read_block())
{
// block
// data
}
我用谷歌搜索了一下是否可以用迭代器来完成,但我无法弄清楚我是否可以拥有一个像这样没有定义开头或结尾的懒惰迭代器。也就是说,它的开头是读取器的当前位置(整数偏移量到字符向量),它的结束是找到标记}
的时间。 我不需要构造任意迭代器,或者反向迭代,或者查看两个迭代器是否相等,因为这纯粹是为了让线性迭代减少重复。
目前每次我想读取一个块时,我都需要重写以下内容:
stream.skip(); // {
while ((token = stream.read()) != "}")
{
// block
// data
}
这变得非常混乱,尤其是当我在块内有块时。为了支持块内的块,迭代器必须全部引用同一读取器的偏移量,以便内部块将推进偏移量,外部块将从该高级偏移量重新开始迭代(在内部完成之后)。
这有可能在C++实现吗?
为了在 for-range 循环中使用,类必须具有返回迭代器的成员函数 begin() 和 end()。
什么是迭代器?满足一组要求的任何对象。有几种迭代器,具体取决于哪些操作允许您。我建议实现一个输入迭代器,这是最简单的:https://en.cppreference.com/w/cpp/named_req/InputIterator
class Stream
{
public:
std::string read() { /**/ }
bool valid() const { /* return true while more tokens are available */ }
};
class FileParser
{
std::string current_;
Stream* stream_;
public:
class iterator
{
FileParser* obj_;
public:
using value_type = std::string;
using reference = const std::string&;
using pointer = const std::string*;
using iterator_category = std::input_iterator_tag;
iterator(FileParser* obj=nullptr): obj_ {obj} {}
reference operator*() const { return obj_->current_; }
iterator& operator++() { increment(); return *this; }
iterator operator++(int) { increment(); return *this; }
bool operator==(iterator rhs) const { return obj_ == rhs.obj_; }
bool operator!=(iterator rhs) const { return !(rhs==*this); }
protected:
void increment()
{
obj_->next();
if (!obj_->valid())
obj_ = nullptr;
}
};
FileParser(Stream& stream): stream_ {&stream} {};
iterator begin() { return iterator{this}; }
iterator end() { return iterator{}; }
void next() { current_ = stream_->read(); }
bool valid() const { return stream_->valid(); }
};
因此,文件结束迭代器由指向任何对象的迭代器表示。
然后你可以像这样使用它:
int main()
{
Stream s; // Initialize it as needed
FileParser parser {s};
for (const std::string& token: parser)
{
std::cout << token << std::endl;
}
}
相关文章:
- 跟随整数索引列表的自定义类迭代器
- 如何在创建自定义迭代器时获得 std::p air 的第一个和第二个?
- 自定义 STL 兼容迭代器,用于迭代 2D 数组类的列
- 无法使用自定义迭代器进行排序
- 比较迭代器会使程序崩溃,而不会在自定义气泡排序实现中出现错误
- 使用迭代器的自定义比较器函数
- 具有迭代器和自定义步长的循环结束条件
- 在C++中使用带有自定义向量的迭代器
- 指向临时对象的自定义迭代器(延迟加载)
- MSVC++ 17 std::copy 期望自定义迭代器的"operator -"
- 如何使用提升范围将自定义迭代器封装在函数中
- 字符串反向迭代器自追加的持久性
- 如何将 std::num_put 与自定义迭代器一起使用?
- 自定义迭代器:如果 a 和 b 的行为不同,如何正确处理距离计算和相等比较
- 迭代器关系运算符出错(带单独链接和迭代器的自定义哈希表)
- std::sort 在我的自定义迭代器上不起作用
- 为自定义数组实现迭代器
- C++自定义惰性迭代器
- 奇怪的编译器错误,说明我的迭代器未定义
- c++迭代器操作符定义