将 next(), hasNext() 迭代器接口变成 begin(), end() 接口

Aki*_*ira 3 c++ iterator c++14

我必须使用我无法更改的外部库。该库以及其他库可以通过其内部逻辑标记特殊格式的文件。令牌生成器提供了一个用于访问令牌的迭代器接口,类似于以下简化示例:

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
    /* ... */
};
Run Code Online (Sandbox Code Playgroud)

我想执行一个迭代包装器所呈现的Tokenizer它允许使用标准的算法库std::copy_ifstd::count等)。更具体地说,如果迭代器包装器满足输入迭代器的要求就足够了。

我目前的试验如下所示:

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;
};
Run Code Online (Sandbox Code Playgroud)

我陷入了像beginand end、相等比较器等函数的实现中。所以,我的问题是:

  • 如何构造一个TokenIterator指示令牌序列结束的实例(即hasNext() == false),以及如何将其与另一个TokenIterator实例进行比较以确定它们是否相同?
  • 如果我从重载operator*()而不是引用返回一个值,这是一个好方法吗?

Fil*_*ipp 5

首先,我建议仔细查看http://www.boost.org/doc/libs/1_65_1/libs/iterator/doc/iterator_facade.html

我发现它大大减少了这样的代码所需的样板数量。

然后,您必须决定如何表示已到达“结束”的迭代器。一种方法是将默认构造的迭代器设为“结束”迭代器。它不包含任何对象,您不能增加或取消引用它。“开始”迭代器则是一个非默认构造的迭代器。它有一个对象,您可以取消引用它。增加这个迭代器只是检查hasNext(). 如果为 true,则将包含的对象设置为next()。如果为 false,则清除包含的对象并使这个迭代器看起来像一个默认构造的迭代器。

operator*. 即使您分配给引用,生命周期扩展也会保留该值,直到引用超出范围。也就是说,任何假定此类引用在多次迭代中仍然有效的代码都会中断,因此请坚持使用 simplefor (auto val : tokens)for (auto& val : tokens).