
"David Abrahams" <dave@boost-consulting.com> wrote in message news:uacwmy7tw.fsf@boost-consulting.com...
"Alex Chovanec" <achovane@engin.umich.edu> writes:
So 'is_iterator<int *>::value' evaluates to true without generating a compile error, as it should.
*Any* iterator can be implemented the same way. An iterator class does not have to have a value_type member!
Ok, you bring up a valid point. I would like to suggest a possible solution to this problem, but the explanation is a bit long, so please bear with me. :-) Originally, I was using the following SFINAE approach in 'is_iterator' to detect member iterator traits: template <typename T> static char test( T *, type_tag<typename T::value_type> * = 0, type_tag<typename T::reference> * = 0, type_tag<typename T::pointer> * = 0, type_tag<typename T::difference_type> * = 0, type_tag<typename T::iterator_category> * = 0 ); static char (& test(...))[2]; I had considered using Boost iterator traits to do the same thing, like this: template <typename T> static char test( T *, type_tag<typename detail::iterator_traits<T>::value_type> * = 0, type_tag<typename detail::iterator_traits<T>::reference> * = 0, type_tag<typename detail::iterator_traits<T>::pointer> * = 0, type_tag<typename detail::iterator_traits<T>::difference_type> * = 0, type_tag<typename detail::iterator_traits<T>::iterator_category> * = 0 ); static char (& test(...))[2]; But I felt that the first approach was clearer, and I reasoned that it would be ok to rely on member traits if I also defined a partial template specialization to handle pointers. It wasn't until I read your last email that I tried the second approach and realized that it doesn't work. It's no surprise that attempting to instantiate 'iterator_traits<T>' causes a compile error when 'T' is not an iterator, but I had assumed that SFINAE would simply remove this overload of 'test' from the set of candidate functions. I see now that SFINAE doesn't work unless you have a valid type on the lefthand side of the '::' operator. So the problem is not that 'iterator_traits<T>::value_type' does not exist; the problem is that 'iterator_traits<T>' cannot be instantiated. But what if 'iterator_traits<T>' were defined in such a way that it can still be instantiated even if 'T' is not an iterator? If 'T' is not an iterator, then 'iterator_traits<T>' can simply be defined to be without any member types. This is easy to do with a little template metaprogramming. The modified primary template for Boost iterator traits might look something like this: template <typename T> struct iterator_traits : public mpl::if_< mpl::or_< has_member_iterator_traits<T>, is_pointer<T> >, std::iterator_traits<T>, empty_iterator_traits >::type {}; Here, 'has_member_iterator_traits' implements my first approach for detecting member iterator traits, and 'empty_iterator_traits' is just an empty type. This definition works for both iterators that have member traits and iterators that are pointers; and it can be specialized for other iterators just as easily as the existing 'iterator_traits'. Now, 'is_iterator' can be defined in terms of Boost iterator traits using the second approach described above. Since 'iterator_traits<T>' can always be instantiated, SFINAE will take care of the rest, and we won't be bothered with unwanted compile errors. What are your thoughts on this approach? Thanks, Alex Chovanec