【问题标题】:Successor of iterator is not necessarily a regular function: how is it possible?迭代器的后继者不一定是正则函数:怎么可能?
【发布时间】:2016-12-06 06:30:26
【问题描述】:

Elements of Programming一书的第 91 页中,Stepanov 和 McJones 说 Iterator 的概念需要一个 successor 函数,但这不一定是常规的,因为

...i = j 并不意味着successor(i) = successor(j)...

(见page online

我理解相反的successor(i) = successor(j) 并不暗示i=j(例如在两个以空结尾的列表中)并且可能没有为某些输入定义successor 函数。但我不明白i = j 怎么可能导致successor(i) != successor(j)

他们指的是什么情况?也许是一些随机(如偶然)跳跃的迭代器?或者一些具有隐藏状态的迭代器,在指向同一个元素(并且在这个意义上比较相等)之后,与另一个迭代器“跳跃”不同。

他们立即跳转到需要常规 successor 函数的改进(ForwardIterator),所以我不清楚。


最初我认为输入迭代器可以具有此属性。但是,我仍然很难看出这是否构成反例:(在 STL 的某个实现中)。

#include <iostream>
#include <sstream>
#include <iterator>
#include <numeric>
#include <cassert>
using std::cout; using std::endl;
int main(){
    std::istream_iterator<int> it1(std::cin); // wait for one input
    std::istream_iterator<int> it2 = it1;
    assert(it1 == it2);
    cout << "*it1 = " << *it1 << endl;
    cout << "*it2 = " << *it2 << endl;
    cout << "now sucessor" << endl;
    ++it1; // wait for one input
    ++it2; // wait for another input
    assert(it1 == it2); // inputs still compare equal !
    cout << "*it1 = " << *it1 << endl;
    cout << "*it2 = " << *it2 << endl;
    assert(it1 == it2); // also here ! and yet they point to different values...
    assert(*it1 == *it2); // assert fails! 
}

(使用 GCC 6.1 编译)

【问题讨论】:

    标签: c++ iterator regular-type


    【解决方案1】:

    考虑将类型iter定义为:

    struct iter { unsigned value; };
    
    inline bool operator==(iter const& x, iter const& y) {
      return x.value == y.value;
    }
    inline bool operator!=(iter const& x, iter const& y) {
      return !(x == y);
    }
    auto source(iter const& x) {
      return x.value;
    }
    iter successor(iter const&) {
      std::random_device engine{};
      std::uniform_int_distribution<unsigned> dist{};
      return {dist(engine)};
    }
    

    IIRC,iter 满足 EoP 的 Iterator 概念的要求:它是 Regularsource 是常规函数,successor 尤其是常规函数。 给定iter 类型的两个对象ij,使得i == j,极有可能是successor(i) != successor(j)

    【讨论】:

    • 是的,这就是我想到的例子。但它看起来很复杂,不知道这是否是他们的想法,或者是否有这样的应用程序。我想可以想象一个随机覆盖序列(重复或不重复元素)的迭代器。
    【解决方案2】:

    一个例子可以是一个successor函数,它消耗一个数据流(正如他们在书中提到的那样)。
    当您阅读了 i-th 元素后,理论上您只能为它调用一次 successor 函数。如果您尝试调用它两次,结果会有所不同。
    简单想象successor(i) 从流中读取下一个元素,即 i-th+1 元素。它实际上意味着消耗它并且它不再可用。如果您再次调用 successor(i),您将从流中获取 i-th+2 元素。
    因此,如果输入相同 (i = j),则无法保证输出相同 (successor(i) = successor(j))。

    【讨论】:

    • 是的,有道理,但是当我想实现一个反例时,输入(istream)迭代器仍然比较相等。更令人困惑的是*it1 != *it2,可能是实现问题。 (请参阅我等式中的新代码)。我知道我不应该将 Stepanov 的公理书与 STL 的普通实现进行比较,但我想知道在实践中这些理想是否仍然适用。
    • 好的,不管操作员的顺序如何,我都在做更多的测试和it1 == it2。看起来在实现中我有两个迭代器将保持相等,只要它们在某个时候被分配。
    • 在上下文中,这个例子看起来更像是一个非常规的source 函数(*)。
    • @alfC 你知道我从你正在阅读的书中得到了这个例子,对吧?这是他们用来解释你问什么的例子。
    • 嗯,是的,但是当我尝试使用来自 STL 的输入迭代器实现一个示例时,我无法做到。诚然,一个真正的 STL 输入迭代器可能不是该情况的忠实表示,但人们怎么知道输入迭代器应该表现或比较相等。我唯一能够真正证明的是 source 不是输入迭代器上的常规函数​​。
    猜你喜欢
    • 1970-01-01
    • 2020-07-23
    • 2021-11-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-07-15
    • 1970-01-01
    相关资源
    最近更新 更多