Не удалось find_if
перегрузить find
? Это как std::binary_search
и друзья делают это...
Почему в стандартной библиотеке есть find и find_if?
Ответ 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
, предикат, который вы передаете, может быть сколь угодно сложным, что дает разработчику библиотеки меньше возможностей оптимизации.
Кроме того, С++ имеет философию "вы не платите за то, что не используете", и обычно вы ожидаете, что не хотите платить за оценку предикатов, если будет проведено простое сравнение.