Reputation: 2426
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; }
};
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
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
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
Reputation: 385108
Now that your base class is a dependent type, so are its members pointer
and reference
.
You need to:
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