As I said in the comments, the solutions presented here are based on the non-portable properties of iterators_traits in some implementations. According to the C ++ 03 and C ++ 11 standards, iterator_traits is defined only for iterators (and the special case of pointers), so any other use is undefined behavior. In particular, the use of iterator_traits<T>::pointer in the SFINAE context is not guaranteed because the iterator_traits<T> instance will refer to T::value_type , T::pointer , T::iterator_category , etc., and this happens Beyond the βimmediate context,β where SFINAE doesn't apply.
C ++ 14 will establish that it should have fixed it (this happened after C ++ 14 with DR 2408 ), but for C ++ 11, a safe way to determine is_iterator is to write a is_iterator that checks all the necessary operations that the iterator must determine. The only operations that all iterators should support are operator* and pre- and post-increment. Unfortunately, there may be types that define those operations that are not valid iterators, so writing the correct attribute is quite difficult.
Jonathan wakely
source share