Reputation: 17920
Given:
struct Iter {
using value_type = int;
using difference_type = int;
using reference = int;
using pointer = int;
using iterator_category = int;
};
The following works fine with libstc++, but fails to compile against libc++ 5.0.0:
#include <iterator>
#include <type_traits>
static_assert(
std::is_same<
std::iterator_traits<Iter>::iterator_category,
Iter::iterator_category
>::value, "");
With the error:
error: no member named '
iterator_category
' in 'std::__1::iterator_traits<Iter>
'std::is_same<std::iterator_traits<Iter>::iterator_category, Iter::iterator_category>::value, "");
The static assertion succeeds if Iter::iterator_category
is one of the standard input categories, e.g. std::input_iterator_tag
.
IMHO it shouldn't fail, because the C++ draft states in [iterator.traits]#2:
If Iterator has valid ([temp.deduct]) member types
difference_type
,value_type
,pointer
,reference
, anditerator_category
,iterator_traits<Iterator>
shall have the following as publicly accessible members:using difference_type = typename Iterator::difference_type; using value_type = typename Iterator::value_type; using pointer = typename Iterator::pointer; using reference = typename Iterator::reference; using iterator_category = typename Iterator::iterator_category;
Otherwise,
iterator_traits<Iterator>
shall have no members by any of the above names.
Can anybody please explain whether this is an implementation bug, or why my expectations are wrong?
Upvotes: 4
Views: 263
Reputation: 303517
We also have, in [std.iterator.tags]:
It is often desirable for a function template specialization to find out what is the most specific category of its iterator argument, so that the function can select the most efficient algorithm at compile time. To facilitate this, the library introduces category tag classes which are used as compile time tags for algorithm selection. They are:
input_iterator_tag
,output_iterator_tag
,forward_iterator_tag
,bidirectional_iterator_tag
andrandom_acces_iterator_tag
. For every iterator of typeIterator
,iterator_traits<Iterator>::iterator_category
shall be defined to be the most specific category tag that describes the iterator's behavior.namespace std { struct input_iterator_tag { }; struct output_iterator_tag { }; struct forward_iterator_tag: public input_iterator_tag { }; struct bidirectional_iterator_tag: public forward_iterator_tag { }; struct random_access_iterator_tag: public bidirectional_iterator_tag { }; }
int
isn't one of those tags, so iterator_traits<Iter>::iterator_category
can't give you back int
. I would suggest that having an invalid iterator category is simply violating the preconditions of iterator_traits
- this doesn't necessarily mean that the library must fail, but it also doesn't mean that failure is a library bug.
However, these preconditions aren't spelled out as explicitly in [iterators] as they are in other parts of the library section. So I'd be inclined to suggest that both libraries are correct, but libc++'s approach to not defining any member aliases in iterator_traits<Iter>
is likely better.
Upvotes: 2