前向迭代器的多次通过保证的强度

Bru*_*uno 6 c++ c++-standard-library language-lawyer

考虑标准中的Forward迭代器的定义(草案n4659,[forward.iterators] /27.2.5):

类或指针类型X满足前向迭代器的要求

  • X 满足输入迭代器的要求(27.2.3),
  • X满足DefaultConstructible要求(20.5.3.1),
  • 如果X是可变迭代器,reference则引用T; if X是一个常量迭代器,reference是一个引用const T,
  • 表97中的表达式是有效的,并具有指示的语义,和
  • 对象类型X提供多次通过保证,如下所述.[注意省略]两个可解除引用的迭代器ab类型X提供多次通过保证,如果:
    • a == b暗示++a == ++b
    • X是指针类型或表达式(void)++X(a), *a等价于表达式*a.

[注意:a == b暗示的要求++a == ++b(对于输入和输出迭代器不是这样)以及通过可变迭代器(适用于输出迭代器)去除对赋值数量的限制允许使用多遍 -具有前向迭代器的定向算法. - 结束说明]

[表97省略]

  • 如果ab是相等的,则要么ab都提领要不然也不是提领.
  • 如果ab都是可解除引用的,那么a == b当且仅当*a*b并且绑定到同一个对象时.

多次通过保证的意图似乎是关于允许以下代码:

*iter <---------------------------------------------------
X iter_copy(iter);                                       |
/* do something with iter_copy */                        |
++iter_copy; ... ++iter_copy;                            |
/* iter has not changed, and *iter now is equivalent     |
 * to *iter before the operations on iter_copy */        |
*iter <---------------------------------------------------
Run Code Online (Sandbox Code Playgroud)

然而,正式地说,多次通过保证似乎只暗示执行iter的副本并递增副本*iter保持不变,并且第二个后续增量iter_copy可能会改变*iter.

现在你的第一个想法可能是"呃,归纳!",但它似乎达不到预期的结果; 它只是说如果我们复制iter_copy并增加副本,那么*iter_copy它就没有改变,但它没有说明原件*iter.

问题:是否可以证明指定的多次通过保证意味着什么?

Bar*_*rry 2

当然,可以提出一种满足所有前向迭代器保证但不是完美的多遍的类型。

class Evil {
    int* p;
    size_t idx;

public:
    using iterator_category = std::forward_iterator_tag;
    using difference_type = std::ptrdiff_t;
    using value_type = int;
    using pointer = int*;
    using reference = int&;

    Evil() : p(nullptr), idx(0) { }
    Evil(int* p, size_t idx) : p(p), idx(idx) { }
    Evil(Evil const& ) = default;
    Evil& operator=(Evil const& ) = default;
    ~Evil() = default;

    // only p participates in comparison
    bool operator==(Evil const& rhs) const {
        return p == rhs.p && idx % 2 == rhs.idx % 2; 
    }
    bool operator!=(Evil const& rhs) const { return !(*this == rhs); }

    // incrementing is sort of destructive
    Evil& operator++() {
        ++idx;
        ++p[idx % 2];
        return *this;
    }
    Evil operator++(int) {
        auto tmp = *this;
        ++*this;
        return tmp;
    }

    int& operator*() { return p[idx % 2]; }
};
Run Code Online (Sandbox Code Playgroud)

让我们看一下要求:

  • a == b暗示++a == ++b。查看。operator++()甚至不影响平等。
  • (void)*a, *a相当于*a. 检查一下,解除引用不会造成破坏。
  • (void)++X(a), *a相当于*a. 查看。递增 1 会更改另一个int,而不是此迭代器当前“指向”的 int。所以这个条件也成立。
  • a == biff*a*b绑定到同一个对象。查看。

但是,(void)++++X(a), *a绝对不等于*a。你会得到同样的int回报,只是更大。

事实上,我可以想出一个不符合保证的可笑的不切实际的迭代器,这可能表明存在一个实际实用的迭代器也不满足保证。那里有很多 C++。