Почему в стандартной библиотеке есть find и find_if?
Не удалось find_if
просто быть перегрузкой find
? Вот как std::binary_search
и друзья делают это...
4 ответа
Предикат - это действительная вещь, которую вы можете найти, чтобы вы могли прийти к неясностям.
Рассматривать 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);
† Сохраняйте умственное чтение.
Вот что сказал Страуструп (язык программирования C++, 18.5.2):
Если
find()
а такжеfind_if()
Если бы у меня было такое же имя, это привело бы к удивительным способностям. В общем,_if
суффикс используется, чтобы указать, что алгоритм принимает предикат.
Что касается того, что именно эта "двусмысленность", Стив Джессоп ответил, что в своем (с самым высоким рейтингом) ответ на этот SO вопрос.
(примечание: этот вопрос на самом деле может квалифицироваться как тот же вопрос, что и этот. Я не достаточно умен в C++ Arcania, чтобы принять решение).
У этого не может быть того же самого имени, потому что была бы двусмысленность. Предположим, что у нас был 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
сделать операцию поиска? Чтобы решить эту проблему, они создали два имени функции.
Вы, конечно, можете реализовать find
с точки зрения find_if
используя какой-то предикат равенства.
Я предполагаю, что настоящая причина в том, что вы можете реализовать find
довольно легко и предоставляют эффективные специализированные реализации для типичных встречаемых типов; если вы используете find_if
предикат, который вы передаете, может быть сколь угодно сложным, что дает разработчику библиотеки меньше возможностей для оптимизации.
Кроме того, в C++ есть философия "вы не платите за то, что не используете", и вы обычно ожидаете, что не захотите платить за оценку предиката, если подойдет простое сравнение.