我必须使用无法更改的外部库。除其他外,该库可以通过其内部逻辑对特殊格式的文件进行标记。 tokenizer 提供了一个迭代器接口(interface)来访问 token ,它看起来像下面的简化示例:
class Tokenizer {
public:
/* ... */
Token token() const; // returns the current token
Token next() const; // returns the next token
bool hasNext() const; // returns 'true' if there are more tokens
/* ... */
};
我想为呈现的 Tokenizer
实现一个迭代器包装器,它允许使用标准 algorithms library (std::copy_if
、std::count
等)。更具体地说,如果迭代器包装器满足 input iterator 的要求就足够了.
我当前的试用版如下所示:
class TokenIterator {
public:
using iterator_category = std::input_iterator_tag;
using value_type = Token;
using difference_type = std::ptrdiff_t;
using pointer = const value_type*;
using reference = const value_type&;
explicit TokenIterator(Tokenizer& tokenizer) :
tokenizer(tokenizer) {
}
TokenIterator& operator++() {
tokenizer.next();
return *this;
}
value_type operator*() {
return tokenizer.token();
}
private:
Tokenizer& tokenizer;
};
我被 begin
和 end
、相等比较器等函数的实现所困。所以,我的问题是:
- 如何构造一个
TokenIterator
实例来指示 token 序列的结尾(即hasNext() == false
)以及如何将它与另一个进行比较code>TokenIterator
实例判断是否相同? - 如果我从
operator*()
的重载中返回一个值而不是引用,这是一个好方法吗?
最佳答案
首先,我建议仔细查看 http://www.boost.org/doc/libs/1_65_1/libs/iterator/doc/iterator_facade.html
我发现它大大减少了此类代码所需的样板文件数量。
然后,您必须决定希望如何表示已到达“结尾”的迭代器。一种方法是使默认构造的迭代器成为“结束”迭代器。它不包含任何对象,您不能递增或取消引用它。
“开始”迭代器是一个非默认构造的迭代器。它有一个对象,您可以取消引用它。递增此迭代器只需检查 hasNext()
。如果为真,则将包含的对象设置为 next()
。如果为 false,则清除包含的对象并使此迭代器看起来像默认构造的迭代器。
operator*
按值返回应该没有任何问题。即使您分配给引用,生命周期延长也会保留该值,直到引用超出范围。也就是说,任何假定此类引用在多次迭代后仍然有效的代码都会中断,因此请坚持使用简单的 for (auto val : tokens)
或 for (auto& val : tokens)
.
关于c++ - 将next()、hasNext()迭代器接口(interface)转为begin()、end()接口(interface),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47403058/