4

単純な不変の双方向反復子を作成しました。

#include <iostream>
#include <memory>
#include <iterator>
#include <vector>
#include <algorithm>

class my_iterator : public std::iterator<std::bidirectional_iterator_tag, int
//, std::ptrdiff_t, int*, int
> {
  int d_val;
public:
  my_iterator() : d_val(0) {}
  my_iterator(int val) : d_val(val) {}

  my_iterator  operator--(int) { d_val--; return my_iterator(d_val + 1); }
  my_iterator &operator--()    { d_val--; return *this; }
  my_iterator  operator++(int) { d_val++; return my_iterator(d_val - 1); }
  my_iterator &operator++()    { d_val++; return *this; }

  int operator*() const { return d_val; }

  bool operator==(my_iterator const  &o) { return d_val == o.d_val; }
  bool operator!=(my_iterator const  &o) { return d_val != o.d_val ; }
};


int main() {
  std::reverse_iterator<my_iterator> reverse_it_begin(25);
  std::reverse_iterator<my_iterator> reverse_it_end(12);
  std::for_each(reverse_it_begin, reverse_it_end, [](int e){ std::cout << e << ' '; });
  std::cout << '\n';
}

operator*() はint referenceではなくintを返すため、反復子は不変です。イテレータが BidirectionalIterator の概念または OutputIterator の概念を満たすかどうかは直交しているため、私の理解ではこれが可能です (4 つの組み合わせすべてが可能です)。

ただし、次のコードではコンパイル時エラーが発生します。

/usr/include/c++/4.9/bits/stl_iterator.h:164:9: error: invalid initialization of non-const reference of type 'std::reverse_iterator<my_iterator>::reference {aka int&}' from an rvalue of type 'int'

完全なコンテキスト:

In file included from /usr/include/c++/4.9/bits/stl_algobase.h:67:0,
                from /usr/include/c++/4.9/bits/char_traits.h:39,
                from /usr/include/c++/4.9/ios:40,
                from /usr/include/c++/4.9/ostream:38,
                from /usr/include/c++/4.9/iostream:39,
                from prog.cpp:1:
/usr/include/c++/4.9/bits/stl_iterator.h: In instantiation of 'std::reverse_iterator<_Iterator>::reference std::reverse_iterator<_Iterator>::operator*() const [with _Iterator = my_iterator; std::reverse_iterator<_Iterator>::reference = int&]':
/usr/include/c++/4.9/bits/stl_algo.h:3755:6:   required from '_Funct std::for_each(_IIter, _IIter, _Funct) [with _IIter = std::reverse_iterator<my_iterator>; _Funct = main()::<lambda(int)>]'
prog.cpp:30:86:   required from here
/usr/include/c++/4.9/bits/stl_iterator.h:164:9: error: invalid initialization of non-const reference of type 'std::reverse_iterator<my_iterator>::reference {aka int&}' from an rvalue of type 'int'
  return *--__tmp;
        ^

Success time: 0 mem

それぞれ BidirectionalIterator と InputIterator を必要とする reverse_iterator と for_each 状態に関する cppreference のページ。両方の要件が満たされていると思いますが、stl は依然として逆参照された値を参照に割り当てます。

stl の for_each/reverse_iterator が、OutputIterator である必要のないイテレータに T &operator*() を期待するのはなぜですか?

PS:コメント行は、参照を値で保存する必要があることを示すことで問題を解決できますが、もちろん非常にハックです。

4

2 に答える 2

5

すべての反復子の反復子要件は、[iterator.iterators] にリストされています。

ここに画像の説明を入力

referenceの typedef を参照しますiterator_traits<my_iterator<..>>

以下のセクションでは、およびaはタイプまたは bの値を示し、タイプおよびを それぞれ参照します[..]Xconst Xdifference_typereference iterator_traits<X>::difference_typeiterator_traits<X>::reference

のプライマリ テンプレートはiterator_traitstypedef をテンプレート引数自体で定義された型にデフォルト設定するだけなので、- のreferencetypedefについて話しているのですが、それmy_iteratorは base から継承され、std::iterator<...>デフォルトでT&.
あなたoperator*は を返しますintが、これは確かに ではありませんint&

intに変換できるため、行のコメントを外すことは InputIterators で問題ありませんint

ここに画像の説明を入力

ただし、ForwardIterators では失敗します - [forward.iterators]/1:

クラスまたはポインター型Xは、次の場合に順方向反復子の要件を満たします。

X可変イテレータの場合reference、 への参照Tです。 ifXは const イテレータ、referenceへの参照const T

于 2015-02-20T14:55:00.207 に答える