Вот фрагменты моего шаблона connected_list:
#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 ;
}
Когда я уйду using...
строка без комментариев, код не компилируется.
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() ) ; }
Без этой строки все компилируется нормально.
вопрос: что происходит, когда я комментирую using difference_type = typename std::iterator_traits< iterator >::difference_type;
в приведенном выше коде (только с такими изменениями код компилируется).
================================================== ========================
res.on.functions / 2.5
- В частности, эффекты не определены в следующих случаях: …
- если неполный тип ([basic.types]) используется в качестве аргумента шаблона при создании экземпляра компонента шаблона, если не указано иное
разрешено для этого компонента.
и исторический обсуждение на что.
Ошибка здесь в том, что тип std::iterator_traits< iterator_base >
все еще неполный и в то время, когда вы хотите получить доступ ::pointer
еще не предусматривает, что pointer
член.
Класс std::iterator_traits<iterator_base>
создается в typename std::iterator_traits< iterator_base >::difference_type
потому что он используется на левой стороне ::
и потому что он еще не был создан. Это запускает создание linked_list<int>::iterator_base
потому что тело iterator_traits
использует этот класс для определения его различных членов typedefs — например, создание экземпляра может происходить в строке, которая выглядит как typedef typename Iterator::value_type value_type;
в стандартной библиотеке.
Далее следует использование std::iterator_traits< iterator_base >::pointer
в вашем вложенном классе. Этот раз, iterator_traits<iterator_base>
уже создается, так что ничего не делается, и ::pointer
ищется. Но так как это еще не было объявлено, оно не может быть найдено.
Обратите внимание, что когда вы закомментируете using
строка, ничто в коде больше не будет создавать экземпляр вложенного тела класса (тело членов шаблонов классов «лениво создается»), так что это не может быть мерой за или против валидности конструкций внутри этого вложенного тела класса ,
#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
{}
На момент объявления Pointer_nah
тип Nah
является неполным типом.
iterator_traits
должен заглянуть внутрь этого типа, чтобы найти его pointer
определение.
Но это, рекурсивно, требует определения iterator_traits<Nah>
,
И так далее.
Но главное: Nah
является неполным в точке, где Pointer_nah
объявлен незавершенный означает, что класс не полностью известен. В частности, его размер здесь не известен, поэтому его нельзя передать sizeof
,
Я подозреваю, что это причина, по которой один из ваших компиляторов воскликнул:
» ошибка: неполный тип не допускается