Grim Fandango
Grim Fandango

Reputation: 2426

I inherit from std::iterator, but compiler does not recognise 'pointer' or 'reference'

I am in the process of making a custom iterator, but I am puzzled on what makes the compiler not recognise the pointer or reference typedefs in the case of a templated iterator implementation.

The following code compiles fine:

#include <iterator>

struct It : std::iterator<std::random_access_iterator_tag, int>
{
    int *v;
    pointer operator-> () { return v; }
    reference operator* () { return *v; }

};

but once I templatize my custom iterator I get errors:

#include <iterator>

template <class T>
struct It2 : std::iterator<std::random_access_iterator_tag, T>
{
    T *v;
    pointer operator-> () { return v; }
    reference operator* () { return *v; }

};

whole code here

error: 'pointer' does not name a type
note: (perhaps 'typename std::iterator<std::random_access_iterator_tag, T>::pointer' was intended)
error: 'reference' does not name a type
...

1> Why can't the compiler see the pointer and reference definitions contained in the std::iterator ?

According to the note, it seems that I shouldn't have bothered using the std::iterator struct, but instead I should have manually copied the typedefs. But that seems too error prone in case the iterator or iterator_traits get an extra typedef in the future.

2. How do you think I should deal with the definition of these traits (pointer, reference etc.) ?

Upvotes: 2

Views: 778

Answers (3)

user743382
user743382

Reputation:

1> Why can't the compiler see the pointer and reference definitions contained in the std::iterator ?

Because the compiler cannot rule out you attempting to provide a specialisation of std::iterator where pointer and reference aren't type definitions, dependent names can never be interpreted as a typedef at template definition time.

2. How do you think I should deal with the definition of these traits (pointer, reference etc.) ?

While explicitly qualifying them with typename every time works, what you can do instead is declare them once as such, and rely on that one declaration in the rest of your It2 definition:

#include <iterator>

template <class T>
struct It2 : std::iterator<std::random_access_iterator_tag, T>
{
    using base = std::iterator<std::random_access_iterator_tag, T>;
    using typename base::pointer;
    using typename base::reference;
    T *v;
    pointer operator-> () { return v; }
    reference operator* () { return *v; }
};

Upvotes: 6

edmz
edmz

Reputation: 8494

The compiler is very clear about the error:

perhaps typename std::iterator<std::random_access_iterator_tag, T>::pointer was intended

because pointer has become a type-dependent name.

Upvotes: 1

Lightness Races in Orbit
Lightness Races in Orbit

Reputation: 385108

Now that your base class is a dependent type, so are its members pointer and reference.

You need to:

  • indicate to the compiler that those words are types
  • indicate to the compiler that those words are member types

You can do it easily:

   typename It2::pointer operator-> () { return v; }
   typename It2::reference operator* () { return *v; }
// ^^^^^^^^^^^^^^

Why? Because C++ is quirky as frak and extremely inexpressive.

Upvotes: 5

Related Questions