Почему `std::string` имеет функцию `find`?

Почему std::string имеет функцию члена find, а std::vector, а друзья не имеют ее?

Что-то не так с использованием std::find в строке?

Ответ 1

Это в основном по историческим причинам, но не только.

Строковая библиотека и STL (которая представляет собой библиотеку контейнеров/алгоритмов, разработанную А. Степановым, которая в итоге стала частью стандартной библиотеки С++) были разработаны независимо, и они приняли различные соглашения.

Однако, поскольку они в конечном итоге оба конвертируются в стандартную библиотеку С++, С++ Standard делает попытку унифицировать эти синтаксические соглашения и позволяет использовать string с алгоритмами STL, поэтому класс string имеет функции-члены, такие как begin() и end() помимо других функций-членов, таких как substr().

Помимо обратной совместимости, в любом случае есть еще одна причина, по которой string предоставляет функции-члены, такие как find(): в отличие от контейнеров, которые предназначены для работы с универсальными алгоритмами, которые обеспечивают доступ к элементам или манипулируют ими, строки в основном рассматриваются как сами ценности, а не как совокупности значений (т.е. последовательности char s). Таким образом, имеет смысл инкапсулировать алгоритмы, которые управляют значениями string в функции-члены класса string.

В своем дизайне стандартная библиотека С++ поддерживает оба этих представления string s: как коллекции значений и самих значений.

UPDATE:

Бит вашего первого предложения "пока std::vector и друзья его не имеют" не совсем правильно. По крайней мере, если вы расширяете диапазон друзей std::vector до std::set, std::multiset, std::map, std::multimap, std::unordered_set и std::unordered_map (другими словами, в значительной степени для всех ассоциативных контейнеры в стандартной библиотеке С++).

У некоторых структур данных действительно есть версия функций некоторых общих STL-алгоритмов на их интерфейсе: это либо указывает на то, что эти алгоритмы имеют более эффективную реализацию, чем их общие экземпляры для этих конкретных структур данных (например, find()) или что требуется специализированная реализация, поскольку общие алгоритмы вообще не могут применяться к этим структурам данных (например, std::remove(), который изменяет значения в контейнере).

Ответ 2

Семантика std::string::find (*) полностью отличается от семантики std::find. В случае алгоритма он найдет элемент внутри контейнера, который, если вы примените к std::string, означает поиск местоположения, для которого символ X.

Функции-члены std::string::find (кроме одного варианта, который принимает один charT), имеют другую цель, они находят подстроки (т.е. последовательность значений, а не одно значение).

Следующий вопрос будет заключаться в том, почему такая перегрузка, которая принимает charT, есть, когда это может быть просто вызов std::find. Как заметил Энди в своем ответе, реализация STL и библиотек строк происходила отдельно. Итераторы затем добавлялись к компоненту std::string. К тому времени, когда итераторы были добавлены в std::string, эта перегрузка уже была там, даже если это не так, семантика все еще немного отличается от std::find тем, что, как и в остальной части std::string::find, вместо итераторов они принимать и возвращать позиции. Это не означает, что нельзя реализовать в терминах другого, только этот код будет более запутанным.

(*) Возьмите меня... прочитайте std::string, как если бы это было написано std::basic_string<>