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

时间:2018-04-18 13:08:49

标签: c++ language-lawyer c++-standard-library

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

  

如果

,类或指针类型X满足前向迭代器的要求      
      
  • X满足输入迭代器(27.2.3),
  • 的要求   
  • X满足DefaultConstructible要求(20.5.3.1),
  •   
  • 如果X是可变迭代器,reference是对T的引用;如果X是常量迭代器,reference是对const T的引用,
  •   
  • 表97中的表达式是有效的,并具有指示的语义和
  •   
  • X类型的对象提供多次通过保证,如下所述。   [注意省略]   如果符合以下条件,则a的两个可解除引用的迭代器bX提供多次通过保证:      
        
    • 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 <---------------------------------------------------

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

现在你的第一个想法可能就是&#34; duh,感应!&#34;,但它似乎达不到预期的结果;它说的是,如果我们复制iter_copy并增加 副本,那么*iter_copy就会保持不变,但它对原始*iter没有任何说明。

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

1 个答案:

答案 0 :(得分: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]; }
};

让我们完成要求:

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

但是,(void)++++X(a), *a绝对不等同于*a。你会得到相同的int,它只会是一个更大的。

我可以想出一个不符合保证的滑稽不切实际的迭代器这一事实可能表明实际的实际的迭代器也不符合保证。那里有很多C ++。