Следующая программа, которая создает пользовательский тег категории итератора, отклоняется clang (используя -stdlib=libc++
), но не другими компиляторами и стандартными реализациями библиотек:
#include <iterator>
struct my_iterator_tag {};
struct my_iterator : std::iterator<my_iterator_tag, int> {};
int main()
{
std::iterator_traits<my_iterator>::value_type x;
return 0;
}
Мне непонятно, запрещает ли стандарт C++ создавать экземпляр std::iterator_traits
с типом итератора, который имеет нестандартную категорию итератора.
Является ли эта программа незаконной?
clang output (при использовании libc++) ниже:
$ clang -stdlib=libc++ test.cpp
test.cpp:9:38: error: no type named 'value_type' in 'std::__1::iterator_traits<my_iterator>'
std::iterator_traits<my_iterator>::value_type x;
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^
1 error generated.
Шаблон std::iterator
определяется следующим образом:
template<class Category, class T, class Distance = ptrdiff_t,
class Pointer = T*, class Reference = T&> struct iterator {
typedef T value_type;
typedef Distance difference_type;
typedef Pointer pointer;
typedef Reference reference;
typedef Category iterator_category;
};
}
Я не вижу ничего плохого в вашем заявлении:
struct my_iterator : std::iterator<my_iterator_tag, int> {};
Итак, свободно говоря, вы в конечном итоге определяете:
struct my_iterator {
// ...
typedef Category my_iterator_tag;
// ...
};
Не вижу ничего плохого в этом. Это действительное объявление.
Теперь давайте взглянем на определение iterator_traits
:
template<class Iterator> struct iterator_traits {
typedef typename Iterator::difference_type difference_type;
typedef typename Iterator::value_type value_type;
typedef typename Iterator::pointer pointer;
typedef typename Iterator::reference reference;
typedef typename Iterator::iterator_category iterator_category;
};
Применяя этот шаблон к Iterator
my_iterator
, я тоже не вижу ничего технически неправильного. Вышеприведенные определения этих шаблонов поднимаются прямо из стандарта. Итак, что касается фактического строго, буквального объявления этих шаблонов в стандарте C++ 11, я не вижу ничего плохого в объявлениях.
Стандарт C++, конечно, определяет пять стандартных категорий итераторов, поэтому, если остальная часть библиотеки C++, необходимо проанализировать это дальше. Я полагаю, что различные вещи, такие как адаптеры итератора, вероятно, будут неопределенным поведением, с чем-либо, кроме пяти стандартных категорий итераторов.
Я не мог найти с беглым взглядом все, что прямо указывает, что использование ничего, кроме пяти предопределенных тегов с std::iterator
и std::iterator_traits
является неопределенным поведением, поэтому в этом только ограниченном примере я бы сказал, что это технически обоснованно, хотя и имеет сомнительную ценность.