
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. -- Dave Abrahams Boost Consulting www.boost-consulting.com