Могут ли использоваться итераторы ввода, если ожидаются форвардные итераторы?

Насколько мне известно, иерархия категорий итераторов выглядит следующим образом:

Random access -> Bi-directional -> Forward -> Input
                                           -> Output

Правильно?

Я всегда думал, что существует правило: если алгоритм ожидает определенный тип итератора, вы можете предоставить итераторы категорий по цепочке, но не вниз. Итак, я читал этот ответ, где ildjarn предлагает предлагаемый (а затем исправленный), используя std::ifstream с std::istream_iterator и std::search для поиска данных в файле a. Я собирался прокомментировать, что вы не можете этого сделать, потому что search ожидает Forward iterators, а istream_iterator - итератор ввода. Но чтобы убедиться, я пробовал это:

std::istringstream iss("Elephant hats for sale.");
std::istream_iterator<char> begin(iss), end;

std::string sub("hat");
auto i = std::search(begin, end, sub.begin(), sub.end());

Я не ожидал, что он скомпилируется, но это произошло. Однако результаты кажутся бесполезными, потому что если я последую за ним с этим:

while(i != end)
{
    std::cout << *i;
    ++i;
}

Нет вывода. Итак, мой вопрос заключается в следующем: мой компилятор ошибочен, разрешив мой вызов search с помощью istream_iterator? Или нет правил, запрещающих подобные вещи?

Ответ 1

Можно ли использовать итераторы ввода, если ожидаются форвардные итераторы?

Нет. Разница между входным итератором и форвардным итератором заключается в том, что итератор ввода является "однопроходным" итератором, но перекрестный итератор является "многопроходным" итератором.

Как только вы продвигаете итератор ввода, вы больше не можете обращаться к предыдущим элементам диапазона. Если вы создадите копию итератора ввода, оба итератора остаются в силе до тех пор, пока вы не наберете один из них; то другой перестает быть действительным.

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

Итак, мой вопрос заключается в следующем: мой компилятор ошибочен для разрешения моего вызова на поиск с помощью istream_iterator?

Нет правила, что компилятор должен отклонить код.

Правило заключается в том, что вы должны обязательно передать правильный тип итератора, который требуется этой функции. Иногда, если вы передаете неправильный тип итератора, вы получаете ошибку компиляции. Иногда программа будет компилироваться, но не будет работать правильно. Иногда все будет работать правильно. Результаты undefined, если вы нарушите требования вызова функции.


Общие алгоритмы обычно налагают требования к их параметрам типа, предполагая, что предоставленные аргументы типа действительно соответствуют требованиям. Так, например, алгоритм, который работает только с итераторами произвольного доступа, будет "применять" это требование, выполняя некоторую операцию, которая работает только с итераторами произвольного доступа (например, it + 1). Если итератор не поддерживает эту операцию (operator+(iterator, int) здесь), код не сможет скомпилироваться.

Проблема заключается в том, что нет способа различать итераторы ввода и итераторы вперед таким образом: вы можете увеличивать и разыгрывать их обоих; разница в том, сколько раз вы можете выполнять каждую из этих операций и последовательность, в которой вы можете выполнять эти операции. Таким образом, такой алгоритм, как std::search, будет использовать *it и ++it, который будет "отлично работать" для итераторов ввода, по крайней мере, в том случае, если код будет компилироваться.

В теории алгоритм может использовать шаблон класса std::iterator_traits, чтобы определить, является ли итератор итератором ввода или форвардным итератором; Я не знаю, будет ли это разрешено стандартом языка С++. Если бы библиотека сделала это, вы могли бы получить ошибку компиляции для своего кода, что было бы лучше.