Приход сюда через несколько лет, где C ++ 11 и C ++ 14 значительно облегчают такие вещи. Итератор по своей сути является разыменовываемым, инкрементным. Если это входной итератор , то также сопоставим. Давайте пойдем с последним - так как это выглядит так, как вы хотите.
Простейшей версией было бы использование void_t
:
template <typename... >
using void_t = void;
Базовый корпус:
template <typename T, typename = void>
struct is_input_iterator : std::false_type { };
Действительная специализация кейса:
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 { };
Псевдоним:
template <typename T>
using is_input_iterator_t = typename is_input_iterator<T>::type;
Нет необходимости полагаться на iterator_category
или использовать утомительный стиль проверки C ++ 03 с использованием разрешения перегрузки. Выражение SFINAE там, где оно есть.
<ч />
Как указывает г-н Уэйкли в комментариях, [iterator.traits] требует, чтобы:
требуется, чтобы, если Iterator
был тип
итератор, типы
iterator_traits<Iterator>::difference_type
iterator_traits<Iterator>::value_type
iterator_traits<Iterator>::iterator_category
определяется как тип разницы итератора, тип значения и категория итератора, соответственно.
Таким образом, мы можем определить нашу черту итератора, чтобы просто проверить это:
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 { };
Если iterator_traits<T>::iterator_category
плохо сформирован, то T
не является итератором.