On March 21st the standards committee voted to approve the deprecation of std::iterator
proposed in P0174:
The long sequence of void arguments is much less clear to the reader than simply providing the expected
typedef
s in the class definition itself, which is the approach taken by the current working draft, following the pattern set in c++14
Before c++17 inheritance from std::iterator
was encouraged to remove the tedium from iterator boilerplate implementation. But the deprecation will require one of these things:
typedef
sauto
rather than depending upon the iterator to declare typesstd::iterator_traits
may be updated to work without inheriting from std::iterator
Can someone enlighten me on which of these options I should expect, as I design custom iterators with an eye towards c++17 compatibility?
Conclusion. std::iterator is deprecated, so we should stop using it. Indeed, the next step after deprecation could be total removal from the language, just like what happened to std::auto_ptr .
The primary purpose of an iterator is to allow a user to process every element of a container while isolating the user from the internal structure of the container. This allows the container to store elements in any manner it wishes while allowing the user to treat it as if it were a simple sequence or list.
The discussed alternatives are clear but I feel that a code example is needed.
Given that there will not be a language substitute and without relying on boost or on your own version of iterator base class, the following code that uses std::iterator
will be fixed to the code underneath.
std::iterator
template<long FROM, long TO> class Range { public: // member typedefs provided through inheriting from std::iterator class iterator: public std::iterator< std::forward_iterator_tag, // iterator_category long, // value_type long, // difference_type const long*, // pointer const long& // reference > { long num = FROM; public: iterator(long _num = 0) : num(_num) {} iterator& operator++() {num = TO >= FROM ? num + 1: num - 1; return *this;} iterator operator++(int) {iterator retval = *this; ++(*this); return retval;} bool operator==(iterator other) const {return num == other.num;} bool operator!=(iterator other) const {return !(*this == other);} long operator*() {return num;} }; iterator begin() {return FROM;} iterator end() {return TO >= FROM? TO+1 : TO-1;} };
(Code from http://en.cppreference.com/w/cpp/iterator/iterator with original author's permission).
std::iterator
template<long FROM, long TO> class Range { public: class iterator { long num = FROM; public: iterator(long _num = 0) : num(_num) {} iterator& operator++() {num = TO >= FROM ? num + 1: num - 1; return *this;} iterator operator++(int) {iterator retval = *this; ++(*this); return retval;} bool operator==(iterator other) const {return num == other.num;} bool operator!=(iterator other) const {return !(*this == other);} long operator*() {return num;} // iterator traits using difference_type = long; using value_type = long; using pointer = const long*; using reference = const long&; using iterator_category = std::forward_iterator_tag; }; iterator begin() {return FROM;} iterator end() {return TO >= FROM? TO+1 : TO-1;} };
Option 3 is a strictly more-typing version of Option 1, since you have to write all the same typedefs
but additionally wrap iterator_traits<X>
.
Option 2 is unviable as a solution. You can deduce some types (e.g. reference
is just decltype(*it)
), but you cannot deduce iterator_category
. You cannot differentiate between input_iterator_tag
and forward_iterator_tag
simply by presence of operations since you cannot reflexively check if the iterator satisfies the multipass guarantee. Additionally, you cannot really distinguish between those and output_iterator_tag
if the iterator yields a mutable reference. They will have to be explicitly provided somewhere.
That leaves Option 1. Guess we should just get used to writing all the boilerplate. I, for one, welcome our new carpal-tunnel overlords.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With