Coming in here a few years later, where C++11 and C++14 make it a lot easier to do such things. An iterator is, at its core, something that is dereferencable, incrementable. If it's an input iterator, then also comparable. Let's go with the latter - since that looks like what you want.
The simplest version would be to use void_t
:
template <typename... >
using void_t = void;
Base case:
template <typename T, typename = void>
struct is_input_iterator : std::false_type { };
Valid case specialization:
template <typename T>
struct is_input_iterator<T,
void_t<decltype(++std::declval<T&>()), // incrementable,
decltype(*std::declval<T&>()), // dereferencable,
decltype(std::declval<T&>() == std::declval<T&>())>> // comparable
: std::true_type { };
Alias:
template <typename T>
using is_input_iterator_t = typename is_input_iterator<T>::type;
No need to rely on iterator_category
or using the tedious C++03 style of check things using overload resolution. Expression SFINAE is where it's at.
As Mr. Wakely points out in the comments, [iterator.traits] requires that:
it is required that if Iterator
is the type of
an iterator, the types
iterator_traits<Iterator>::difference_type
iterator_traits<Iterator>::value_type
iterator_traits<Iterator>::iterator_category
be defined as the iterator’s difference type, value type and iterator category, respectively.
So we can define our iterator trait to simply check for that:
template <class T, class = void>
struct is_iterator : std::false_type { };
template <class T>
struct is_iterator<T, void_t<
typename std::iterator_traits<T>::iterator_category
>> : std::true_type { };
If iterator_traits<T>::iterator_category
is ill-formed, then T
is not an iterator.