2438. std::iterator inheritance shouldn't be mandated

Section: D.14.1 [depr.iterator.basic] Status: C++17 Submitter: Stephan T. Lavavej Opened: 2014-10-01 Last modified: 2017-07-30

Priority: 3

View all issues with C++17 status.

Discussion:

For LWG convenience, nine STL iterators are depicted as deriving from std::iterator to get their iterator_category/etc. typedefs. Unfortunately (and unintentionally), this also mandates the inheritance, which is observable (not just through is_base_of, but also overload resolution). This is unfortunate because it confuses users, who can be misled into thinking that their own iterators must derive from std::iterator, or that overloading functions to take std::iterator is somehow meaningful. This is also unintentional because the STL's most important iterators, the container iterators, aren't required to derive from std::iterator. (Some are even allowed to be raw pointers.) Finally, this unnecessarily constrains implementers, who may not want to derive from std::iterator. (For example, to simplify debugger views.)

We could add wording to 99 [iterator.basic] saying that any depicted inheritance is for exposition only, but that wouldn't really solve reader confusion. Replacing the depicted inheritance with direct typedefs will prevent confusion. Note that implementers won't be required to change their code — they are free to continue deriving from std::iterator if they want.

(Editorial note: The order of the typedefs follows the order of std::iterator's template parameters.)

[Urbana 2014-11-07: Move to Ready]

Proposed resolution:

This wording is relative to N3936.

  1. Change [storage.iterator], class template raw_storage_iterator synopsis, as depicted:

    template <class OutputIterator, class T>
    class raw_storage_iterator
      : public iterator<output_iterator_tag,void,void,void,void> {
    public:
      typedef output_iterator_tag iterator_category;
      typedef void value_type;
      typedef void difference_type;
      typedef void pointer;
      typedef void reference;
    
      explicit raw_storage_iterator(OutputIterator x);
      […]
    };
    
  2. Change 27.5.1.1 [reverse.iterator], class template reverse_iterator synopsis, as depicted (editorial note: this reorders "reference, pointer" to "pointer, reference" and aligns whitespace):

    template <class Iterator>
    class reverse_iterator : public 
      iterator<typename iterator_traits<Iterator>::iterator_category,
      typename iterator_traits<Iterator>::value_type,
      typename iterator_traits<Iterator>::difference_type,
      typename iterator_traits<Iterator>::pointer,
      typename iterator_traits<Iterator>::reference> {
    public:
      typedef Iterator iterator_type;
      typedef typename iterator_traits<Iterator>::difference_type difference_type;
      typedef typename iterator_traits<Iterator>::reference reference;
      typedef typename iterator_traits<Iterator>::pointer pointer;
      typedef Iterator                                              iterator_type;
      typedef typename iterator_traits<Iterator>::iterator_category iterator_category;
      typedef typename iterator_traits<Iterator>::value_type        value_type;
      typedef typename iterator_traits<Iterator>::difference_type   difference_type;
      typedef typename iterator_traits<Iterator>::pointer           pointer;
      typedef typename iterator_traits<Iterator>::reference         reference;
    
      reverse_iterator();
      […]
    };
    
  3. Change 27.5.2.1 [back.insert.iterator], class template back_insert_iterator synopsis, as depicted:

    template <class Container>
    class back_insert_iterator : 
      public iterator<output_iterator_tag,void,void,void,void> {
    protected:
      Container* container;
    
    public:
      typedef output_iterator_tag iterator_category;
      typedef void value_type;
      typedef void difference_type;
      typedef void pointer;
      typedef void reference;
      typedef Container container_type;
      explicit back_insert_iterator(Container& x);
      […]
    };
    
  4. Change 27.5.2.3 [front.insert.iterator], class template front_insert_iterator synopsis, as depicted:

    template <class Container>
    class front_insert_iterator : 
      public iterator<output_iterator_tag,void,void,void,void> {
    protected:
      Container* container;
    
    public:
      typedef output_iterator_tag iterator_category;
      typedef void value_type;
      typedef void difference_type;
      typedef void pointer;
      typedef void reference;
      typedef Container container_type;
      explicit front_insert_iterator(Container& x);
      […]
    };
    
  5. Change 27.5.2.5 [insert.iterator], class template insert_iterator synopsis, as depicted:

    template <class Container>
    class insert_iterator : 
      public iterator<output_iterator_tag,void,void,void,void> {
    protected:
      Container* container;
      typename Container::iterator iter;
    
    public:
      typedef output_iterator_tag iterator_category;
      typedef void value_type;
      typedef void difference_type;
      typedef void pointer;
      typedef void reference;
      typedef Container container_type;
      insert_iterator(Container& x, typename Container::iterator i);
      […]
    };
    
  6. Change 27.6.1 [istream.iterator], class template istream_iterator synopsis, as depicted:

    template <class T, class charT = char, class traits = char_traits<charT>,
      class Distance = ptrdiff_t>
    class istream_iterator : 
      public iterator<input_iterator_tag, T, Distance, const T*, const T&> {
    public:
      typedef input_iterator_tag iterator_category;
      typedef T value_type;
      typedef Distance difference_type;
      typedef const T* pointer;
      typedef const T& reference;
      […]
    };
    
  7. Change 27.6.2 [ostream.iterator], class template ostream_iterator synopsis, as depicted:

    template <class T, class charT = char, class traits = char_traits<charT>>
    class ostream_iterator : 
      public iterator<output_iterator_tag, void, void, void, void> {
    public:
      typedef output_iterator_tag iterator_category;
      typedef void value_type;
      typedef void difference_type;
      typedef void pointer;
      typedef void reference;
      […]
    };
    
  8. Change 27.6.3 [istreambuf.iterator], class template istreambuf_iterator synopsis, as depicted:

    template <class charT = char, class traits = char_traits<charT> >
    class istreambuf_iterator : 
      public iterator<input_iterator_tag, charT,
                      typename traits::off_type, unspecified, charT> {
    public:
      typedef input_iterator_tag iterator_category;
      typedef charT value_type;
      typedef typename traits::off_type difference_type;
      typedef unspecified pointer;
      typedef charT reference;
      […]
    };
    
  9. Change 27.6.4 [ostreambuf.iterator], class template ostreambuf_iterator synopsis, as depicted (editorial note: this removes a redundant "public:"):

    template <class charT = char, class traits = char_traits<charT>>
    class ostreambuf_iterator : 
      public iterator<output_iterator_tag, void, void, void, void> {
    public:
      typedef output_iterator_tag iterator_category;
      typedef void value_type;
      typedef void difference_type;
      typedef void pointer;
      typedef void reference;
      […]
    public:
      […]
    };