Почему в стандартной библиотеке есть find и find_if?

Не удалось find_if перегрузить find? Это как std::binary_search и друзья делают это...

Ответ 1

Предикат - это правильная вещь, которую можно найти, чтобы вы могли прийти к двусмысленности.


Рассмотрим find_if, переименованный find, тогда у вас есть:

template <typename InputIterator, typename T>
InputIterator find(InputIterator first, InputIterator last, const T& value);

template <typename InputIterator, typename Predicate>
InputIterator find(InputIterator first, InputIterator last, Predicate pred);

Что будет сделано, тогда:

find(c.begin(), c.end(), x); // am I finding x, or using x to find?

Вместо того, чтобы пытаться придумать какое-то сложное решение для дифференциации на основе x (которое не всегда можно сделать *), проще просто отделить их.

* Это было бы неоднозначно, независимо от того, какая у вас схема или насколько она может быть:

struct foo
{
    template <typename T>
    bool operator()(const T&);
};

bool operator==(const foo&, const foo&);

std::vector<foo> v = /* ... */;
foo f = /* ... */; 

// f can be used both as a value and as a predicate
find(v.begin(), v.end(), f); 

† Сохранить чтение разума.

Ответ 2

Вот что сказал Страуступ (Язык программирования С++, 18.5.2):

Если find() и find_if() имели одно и то же имя, неожиданные махинации. В целом, Суффикс _if используется для указания того, что algrithm берет предикат.

Что касается именно этой "двусмысленности", Стив Джессоп ответил, что в своем (наивысшем рейтинге) ответе на этот SO вопрос.

(обратите внимание: этот вопрос действительно может рассматриваться как тот же вопрос, что и этот. Я не достаточно умен в С++ arcania, чтобы решить).

Ответ 3

Он не может иметь одно и то же имя, потому что будет двусмысленность. Предположим, что у нас была перегрузка find вместо find_if. Тогда предположим:

// Pseudo-code
struct finder
{
    bool operator()(const T&) const { ... }
    bool operator==(const finder& right) const { ... }
}

std::vector<finder> finders;

finder my_finder;

std::find(finders.begin(), finders.end(), my_finder);

find не сможет устранить несогласованность: должен ли он попытаться найти finder в контейнере или использовать finder для выполнения операции поиска? Чтобы решить эту проблему, они создали два имени функции.

Ответ 4

на вершине вышеупомянутых ответов,

" if " в " find_if " дает немедленное указание на результат, основанный на "true" или "false".

Ниже простой пример с использованием find_if работает хорошо, лямбда сравнивает и возвращает true:

vector<int> v = {62,64,66,68};
auto it = std::find_if(v.begin(),v.end(),[](const int& ivec){return ivec == 68;});

Теперь попробуйте то же самое с find, как показано ниже, и запишите сообщение об ошибке компилятора о сравнении. find предназначен для поиска по значению, а не по условию.

auto it2 = std::find(v.begin(),v.end(),[](const int& ivec){return ivec == 68;});//Compiler error.

Ответ 5

Вы можете, конечно, реализовать find в терминах find_if, используя какой-то предикат равенства.

Я бы предположил, что реальная причина заключается в том, что вы можете легко реализовать find и предоставить специализированные реализации для типичных встречающихся типов; если вы используете find_if, предикат, который вы передаете, может быть сколь угодно сложным, что дает разработчику библиотеки меньше возможностей оптимизации.

Кроме того, С++ имеет философию "вы не платите за то, что не используете", и обычно вы ожидаете, что не хотите платить за оценку предикатов, если будет проведено простое сравнение.