Volodymyr Boyko
Volodymyr Boyko

Reputation: 1581

no type named ‘pointer’ in struct std::iterator_traits<...>

Here are the fragments of my linked_list template :

#include <iostream>
#include <iterator>

template < class >
struct linked_list {
    struct iterator_base : public std::iterator< std::bidirectional_iterator_tag , int >
    {  
        typename std::iterator_traits< iterator_base >::pointer operator -> () const {
            std::cerr << __func__ ; 
            return nullptr ; } ;
    };
    using difference_type = typename std::iterator_traits< iterator_base >::difference_type ;
} ;

int main ()
{
    int * inullptr = linked_list< int >::iterator_base().operator->() ;
    return 0 ;
}

When I leave using... line uncommented, the code doesn't compile.

g++5.4 :

list2.cxx:105:66: error: no type named ‘pointer’ in ‘struct std::iterator_traits<linked_list<int>::iterator_base<(linked_list<int, std::allocator<int> >::constantness)1u> >’
          typename std::iterator_traits< iterator_base >::pointer operator -> () const { return &( to_obj_node( current_node_ ) -> object() ) ; }

icpc :

list.cxx(105): error: incomplete type is not allowed typename std::iterator_traits< iterator_base >::pointer operator -> () const { return &( to_obj_node( current_node_ ) -> object() ) ; }

Without that line all compiles fine.

the question is : What happens, when i'm commenting using difference_type = typename std::iterator_traits< iterator >::difference_type; in above code ( only with such changes code compiles ).?

========================================================================== res.on.functions/2.5

  1. In particular, the effects are undefined in the following cases:...
    1. if an incomplete type ([basic.types]) is used as a template argument when instantiating a template component, unless specifically allowed for that component.

and historical discussion on that.

Upvotes: 0

Views: 3730

Answers (2)

Johannes Schaub - litb
Johannes Schaub - litb

Reputation: 507115

The error here is that the type std::iterator_traits< iterator_base > is still incomplete and at the time that you want to access ::pointer does not yet provide that pointer member.

The class std::iterator_traits<iterator_base> is being instantiated by typename std::iterator_traits< iterator_base >::difference_type, because it's used on the left side of a ::, and because it has not yet been instantiated. This triggers the instantiation of linked_list<int>::iterator_base because the body of iterator_traits uses that class to define its various member typedefs - for example the instantiation could happen at a line that looks like typedef typename Iterator::value_type value_type; in the Standard library.

What follows is the use of std::iterator_traits< iterator_base >::pointer in your nested class. This time, iterator_traits<iterator_base> is already being instantiated, so nothing is done, and ::pointer is searched. But since that wasn't declared yet, it can't found.

Note that when you comment-out the using line, nothing in the code will instantiate the nested class body anymore (the body of members of class templates are "lazily instantiated"), so this can't be a measure for or against the validity of the constructs inside of that nested class body.

Upvotes: 1

Cheers and hth. - Alf
Cheers and hth. - Alf

Reputation: 145359

#include <iterator>

struct OK_1: std::iterator<std::bidirectional_iterator_tag, int> {};
using Pointer_1 = typename std::iterator_traits<OK_1>::pointer;

struct Nah
{
    using Pointer_nah = typename std::iterator_traits<Nah>::pointer;    //!
};

auto main() -> int
{}

At the point of declaration of Pointer_nah, the type Nah is an incomplete type.

iterator_traits has to look inside that type in order to find its pointer definition.

But that, recursively, requires the definition of iterator_traits<Nah>.

And so on.

But, main point: Nah is incomplete at the point where Pointer_nah is declared. Incomplete means that the class is not fully known. In particular its size is not known here, so it can't be passed to sizeof.

I suspect that that's the reason why one of your compilers exclaimed,

error: incomplete type is not allowed

Upvotes: 0

Related Questions