
On Apr 16, 2006, at 5:56 PM, David Abrahams wrote:
Howard Hinnant <howard.hinnant@gmail.com> writes:
Actually in this particular case, all we need is a more smartly designed std::iterator_traits class:
Spec: --- template <class Iterator> struct iterator_traits { };
However if Iterator has the nested types: difference_type, value_type, pointer, reference and iterator_category, and if Iterator::iterator_category (if it exists) is implicitly convertible to either std::input_iterator_tag, or std::output_iterator_tag, then the struct iterator_traits is instead:
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; };
Plus the pointer specializations... Plus any user-defined specializations... ---
Such an iterator_traits is easy to implement today with has_member_* and is_convertible. And now you can say iterator_traits<any type at all>. The instantiation always compiles and may or may not have the nested typedefs.
Then you can make an is_input_iterator trait:
A type T is an input iterator if iterator_traits<T> has a member called iterator_category that is convertible to std::input_iterator_tag.
...which will fail even for some types that are legit members of std:: in C++98, like
std::iterator<std::input_iterator_tag, int>
(false positive), not to mention types that inherit privately from types like the one above, or just have those names as private members (compile-time error).
I don't mean to rain on this parade every time you bring up the idea, Howard; it's a nice hack. I just don't want anyone to be confused about that: it's a nice hack that works most of the time... and sometimes breaks.
Sure, but now we're in the area of intentionally breaking the system. Concepts will not be invulnerable to deceptive coding either. There's no structural difference between a single pass iterator and a multi pass iterator for Concepts to check. Unless I'm really missing something, you have to depend upon some kind of declarative statement: "I'm a single pass iterator!" Concepts should make it much easier to build and manipulate types of types, and do a better job of it than just checking a single tag. But I don't see a way to eliminate the need to ultimately trust that some tag really means what we think it means. Put another way, the chances of std::iterator<std::input_iterator_tag, int> being an honest (not test case, not intentional abuse) false positive in the wild for is_input_iterator as I described it is probably somewhere around 0.0001%. Concepts will better those odds by another factor of 100, or maybe even 1000. But won't eliminate the possibility. -Howard