Это совершенно разные алгоритмы: find_if
ищет линейно для первого элемента, для которого предикат является истинным, binary_search
использует преимущество, что диапазон сортируется для проверки в логарифмическом времени если в нем задано значение.
Предикат для binary_search
указывает функцию, в соответствии с которой упорядочивается диапазон (вы, скорее всего, захотите использовать тот же предикат, который вы использовали для его сортировки).
Вы не можете воспользоваться сортировкой для поиска значения, удовлетворяющего некоторому совершенно не связанному предикату (вам все равно придется использовать find_if
). Однако обратите внимание, что с отсортированным диапазоном вы можете сделать больше, чем просто проверить существование с lower_bound
, upper_bound
и equal_range
.
Интересен вопрос, какова цель std::binary_function
.
Все, что он делает, это предоставляет typedefs для result_type
, first_argument_type
и second_argument_type
. Это позволило бы пользователям, используя функтор в качестве аргумента шаблона, обнаруживать и использовать эти типы, например,
template <class T, class BinaryFunction>
void foo(const T& a, const T& b, BinaryFunction f)
{
//declare a variable to store the result of the function call
typename BinaryFunction::result_type result = f(a, b);
//...
}
Однако я думаю, что единственное место, где они используются в стандартной библиотеке, - это создание других оболочек функторов, таких как bind1st
, bind2nd
, not1
, not2
. (Если бы они использовались для других целей, люди бы кричали на вас всякий раз, когда вы использовали функцию в качестве функтора, поскольку это было бы непереносимо.)
Например, binary_negate
может быть реализовано как (GCC):
template<typename _Predicate>
class binary_negate
: public binary_function<typename _Predicate::first_argument_type,
typename _Predicate::second_argument_type, bool>
{
protected:
_Predicate _M_pred;
public:
explicit
binary_negate(const _Predicate& __x) : _M_pred(__x) { }
bool
operator()(const typename _Predicate::first_argument_type& __x,
const typename _Predicate::second_argument_type& __y) const
{ return !_M_pred(__x, __y); }
};
Конечно, operator()
может быть просто шаблоном, и в этом случае эти typedefs будут ненужными (какие-либо недостатки?). Вероятно, существуют также методы метапрограммирования, позволяющие выяснить типы аргументов, не требуя, чтобы пользователь явно их определял. Я полагаю, что это немного отразится на мощи, которую дает C ++ 0x - например, когда я хотел бы реализовать отрицатель для функции любой арности с переменными шаблонами ...
(IMO функторы C ++ 98 немного негибки и примитивны по сравнению, например, с std::tr1::bind
и std::tr1::mem_fn
, но, вероятно, в то время поддержка компилятором методов метапрограммирования, необходимых для выполнения этой работы, была не такой хорошей, и, возможно, методы все еще открывались.)