11

It appears that the iterator adaptor reverse_iterator doubly defines most of its nested types. In particular, it inherits publicly from std::iterator which exposes iterator_category, value_type, difference_type, pointer and reference. Except for iterator_category and value_type, these are all explicitly typedef'ed again in the class definition.

24.5.1.1 Class template reverse_iterator [reverse.iterator]

namespace std {
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;
  // ... rest of the class
};

Question: why the repetitive definition? Is this just for purposes of exposition, or is there more to it? And why not redefine iterator_category and value_type?

TemplateRex
  • 69,038
  • 19
  • 164
  • 304
  • 4
    It doesn't redefine `value_type` either. Anyway, this question is going to become moot soon, thanks to [LWG 2438](http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-active.html#2438). – T.C. Mar 17 '15 at 20:29
  • @T.C. thanks for digging up that DR. I updated the Q. If you make it an answer, I'll accept. – TemplateRex Mar 17 '15 at 20:33
  • 5
    Maybe it has to do with dependent name lookup? The names inherited from `iterator` are not visible in all cases, since it's a dependent base class. – dyp Mar 17 '15 at 20:36
  • @dyp probably. I pull the types I use from my template bases in like that too. – Yakk - Adam Nevraumont Mar 17 '15 at 20:37
  • this probably boils down to the base being a *dependent-name*, which further means that it is easier to write `pointer` than `typename iterator_traits::pointer` when writing the definition of `reverse_iterator`. – Filip Roséen - refp Mar 17 '15 at 20:43

2 Answers2

10

For a while now, they've been moving away from using std::iterator as a base class, and toward just specifying that each iterator must define the correct type names.

When they specify the base class in the standard, that constrains implementations to implement the class that way, even though the only real intent was to specify that the iterator needs to define some names. In particular, you could is_base_of to determine whether std::iterator is a base class of std::reverse_iterator. No, there's nothing polymorphic, so it's pretty silly and pointless to do so, but if you do so, the current standard says it must return true.

It looks (to me) like this is more or less an accidental halfway-point in the process of moving from (more or less accidentally) requiring the use of std::iterator as a base class, and simply specifying the names that must be defined in std::reverse_iterator (and various other iterators as well, of course).

For those who care, the history of this includes:

N3931
Issue 2438

There's also so related discussion papers about deprecating unary_function and binary_function:

N3145
N3198

These were provided for roughly the same reasons as std::iterator (i.e., just to provide some typedefs in a derived class) so the reasoning behind removing them is fairly pertinent to ceasing to use std::iterator as a base class.

Jerry Coffin
  • 476,176
  • 80
  • 629
  • 1,111
  • Tricky to call `is_base_of` as neither are types. ;) When using `std::iterator` myself I tend to pull in the definitions I use, as I cannot use them internally (due to dependent name lookup) if I am myself a template. – Yakk - Adam Nevraumont Mar 17 '15 at 20:37
  • The definition of `reverse_iterator` has already been like this in the C++03 IS. – dyp Mar 17 '15 at 20:40
  • @dyp: Given the state of Google Groups anymore, I'm not sure I could find it, but I remember a Usenet thread that seems like it was around 1996 or so, already arguing that these were a poor idea, and the typedefs should just be specified directly. – Jerry Coffin Mar 17 '15 at 20:57
  • so the answer is that it's the `std::iterator<>` that is superfluous, not the in-class `typedef`. – TemplateRex Mar 17 '15 at 21:08
  • @TemplateRex: Yes, pretty much. – Jerry Coffin Mar 17 '15 at 21:22
3

This is more of a guess, but all those redundant typedefs declare types that are used within specification of the class body of reverse_iterator. For example (C++03 IS):

pointer operator->() const;
reference operator[](difference_type n) const;

Since iterator<..> is a dependent base class, it won't be searched for the names pointer and reference. So typedefing those names makes the remaining spec simpler:

typename iterator_traits<Iterator>::pointer operator->() const;
typename iterator_traits<Iterator>::reference operator[](typename iterator_traits<Iterator>::difference_type n) const;

On the other hand, value_type does not appear within the class body, therefore it doesn't need a redundant typedef.

dyp
  • 38,334
  • 13
  • 112
  • 177
  • Of course, this doesn't answer the question why to derive from `iterator` in the first place.. but once that's given, the `typedef`s are an implication for convenience. – dyp Mar 17 '15 at 20:51
  • The return type of `operator[]` is unspecified in C++14 IS, btw. – dyp Mar 17 '15 at 20:53