Какие они?
std :: unary_function и std :: binary_function являются базовыми структурами для создания адаптируемых объектов функций. Слово adaptable означает, что они предоставляют необходимые определения типов для использования вместе со стандартными функциональными адаптерами, такими как std :: not1 , std :: not2 , std :: bind1st , std :: bind2nd .
Когда мне нужно их использовать?
Вы можете использовать их каждый раз, когда вам нужно использовать объект пользовательской функции вместе со стандартным адаптером функций.
У вас есть пример?
Давайте рассмотрим некоторые примеры (я знаю, они искусственные. С другой стороны, я надеюсь, что они довольно наглядны).
Пример 1.
Предположим, что вы хотите напечатать все строки в векторе с их длинами не менее определенного порогового значения и вывести их в std :: cout .
Можно использовать следующий функциональный объект:
class LengthThreshold
{
public:
LengthThreshold(std::size_t threshold) : threshold(threshold) {}
bool operator()(const std::string& instance) const
{
return (instance.size() < threshold);
}
private:
const std::size_t threshold;
};
Теперь задача довольно проста и может быть выполнена алгоритмом std :: remove_copy_if :
// std::size_t threshold is defined somewhere
std::remove_copy_if(some_strings.begin(), some_strings.end(),
std::ostream_iterator<std::string>(std::cout, "\n"),
LengthThreshold(threshold)
);
Что если вы хотите использовать один и тот же функциональный объект для печати всех строк с их длинами , строго меньшими , чем пороговое значение?
Очевидным решением, которое мы можем придумать, является использование функционального адаптера std :: not1 :
// std::size_t threshold is defined somewhere
std::remove_copy_if(some_strings.begin(), some_strings.end(),
std::ostream_iterator<std::string>(std::cout, "\n"),
std::not1(LengthThreshold(threshold))
);
Фактически, приведенный выше код не будет компилироваться, потому что наш LengthThreshold не адаптируется и не имеет typedefs, которые необходимы для std :: not1 .
Чтобы сделать его адаптируемым, нам нужно наследовать от std :: unary_function :
class LengthThreshold : public std::unary_function<std::string, bool>
{
// Function object's body remains the same
}
Теперь наш первый пример работает как шарм.
Пример 2.
Давайте изменим наш предыдущий пример. Предположим, мы не хотим хранить порог внутри объекта функции. В таком случае мы можем изменить объект функции с унарного предиката на двоичный предикат:
class LengthThreshold : public std::binary_function<std::string, std::size_t, bool>
{
public:
bool operator()(const std::string& lhs, std::size_t threshold) const
{
return lhs.size() < threshold;
}
};
И используйте std :: bind2nd функциональный адаптер:
// std::size_t threshold is defined somewhere
std::remove_copy_if(some_strings.begin(), some_strings.end(),
std::ostream_iterator<std::string>(std::cout, "\n"),
std::bind2nd(LengthThreshold(), threshold)
);
А как насчет C ++ 11 и выше?
Все примеры, приведенные выше, намеренно используют только C ++ 03 .
Причина в том, что std :: unary_function и std :: binary_function устарели с C ++ 11 и полностью удалены из C ++ 17 .
Это произошло с появлением более обобщенных и гибких функций, таких как std :: bind , которые наследуют от std :: unary_function и std :: binary_function излишний.