87

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 typedefs in the class definition itself, which is the approach taken by the current working draft, following the pattern set in

Before inheritance from std::iterator was encouraged to remove the tedium from iterator boilerplate implementation. But the deprecation will require one of these things:

  1. An iterator boilerplate will now need to include all required typedefs
  2. Algorithms working with iterators will now need to use auto rather than depending upon the iterator to declare types
  3. Loki Astari has suggested that std::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 compatibility?

16
  • 8
    @FirstStep I would hope to get an answer that would not be opinion based. If the standard committee is deprecating a class I depend on next year I'd hope they'd have a direction they are channeling me towards right now. Commented May 4, 2016 at 15:20
  • 2
    Just because they are deprecating it does not mean you can't keep using it for a while. Commented May 4, 2016 at 15:24
  • 4
    The iterators in the standard library have gone for option 1. Commented May 4, 2016 at 15:29
  • 1
    @LokiAstari - it's even weaker than that. Formally, deprecation is a notice that something might go away in the future. That's all. Note that the standard C headers have been deprecated in C++ since 1998. Commented May 4, 2016 at 15:46
  • 2
    @JonathanMee - I use std::iterator because it's convenient. I'll continue to use it until I can't. Commented May 4, 2016 at 16:06

2 Answers 2

82

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.

With 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).

Without 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;}
};
Sign up to request clarification or add additional context in comments.

2 Comments

@AmirKirsh operator* should return reference, you need an operator-> returning a pointer even though it doesn't make sense for a long
I found a pretty fantastic article about it here, too, that outlines the justifications.
34

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.

24 Comments

If you really like what std::iterator does, you can trivially write your own version. So the risk of carpal-tunnel is highly overblown.
@JonathanMee That doesn't make any sense.
@JonathanMee Dude. "Iterator" and "Input Iterator" are not equivalent.
@TemplateRex It was a joke. Regardless, it seems silly to deprecate std::iterator in favor of... everyone now writing their own copy of std::iterator to solve that problem anyway.
related: stackoverflow.com/q/29108958/819272 It's a more general trend in the Standard to remove silly base classes only containing typedefs (unary_function etc.)
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.