Подтвердить что ты не робот

Как проверить, что прошедший Iterator является итератором с произвольным доступом?

У меня есть следующий код, который выполняет некоторую арифметику итератора:

template<class Iterator>
void Foo(Iterator first, Iterator last) {
  typedef typename Iterator::value_type Value;
  std::vector<Value> vec;
  vec.resize(last - first);
  // ...
}

Выражение (last - first) работает (AFAIK) только для итераторов произвольного доступа (например, из vector и deque). Как я могу проверить код, который переданный итератор отвечает этому требованию?

4b9b3361

Ответ 1

Если Iterator - итератор с произвольным доступом, то

std::iterator_traits<Iterator>::iterator_category

будет std::random_access_iterator_tag. Самый простой способ реализовать это, вероятно, создать второй шаблон функции и вызвать Foo:

template <typename Iterator>
void FooImpl(Iterator first, Iterator last, std::random_access_iterator_tag) { 
    // ...
}

template <typename Iterator>
void Foo(Iterator first, Iterator last) {
    typedef typename std::iterator_traits<Iterator>::iterator_category category;
    return FooImpl(first, last, category());
}

Это имеет то преимущество, что вы можете перегрузить FooImpl для разных категорий итераторов, если хотите.

Скотт Мейерс обсуждает эту технику в одной из эффективных книг на C++ (я не помню, какой из них).

Ответ 2

В дополнение к отправке тегов вы можете напрямую сравнивать категорию с std::random_access_iterator_tag с помощью std::is_same_v:

using category = typename std::iterator_traits<Iterator>::iterator_category;
if constexpr (std::is_same_v<category, std::random_access_iterator_tag>) {
  vec.resize(last - first);
}

Иногда это может привести к более четкому и сжатому коду, особенно если только небольшая часть вашей реализации (например, сохранение размера вектора) зависит от категории итератора.