Подтвердить что ты не робот

Для чего нужна функция unary_function и binary_function?

Я прочитал учебники о двоичных и унарных функциях. Я понял их структуру, но я не мог себе представить, в каком случае мне нужны эти функции. Можете ли вы привести пример их использования.

http://www.cplusplus.com/reference/std/functional/unary_function/

http://www.cplusplus.com/reference/std/functional/binary_function/

4b9b3361

Ответ 1

Это не функции, это классы (структуры, фактически, но не имеющие значения). Когда вы определяете свои собственные двоичные функции для использования с алгоритмами STL, вы получаете их из этих классов, чтобы автоматически получить все typedefs.

например.

struct SomeFancyUnaryFunction: public std::unary_function<Arg_t, Result_t>
{
   Result_t operator ()(Arg_t const &)
   {
      ...
   }
};

теперь вам не нужно вручную предоставлять typedefs для argument_type, result_type и т.д. Эти структуры, как и структура iterator, существуют только для нашего удобства, чтобы повторно использовать typedefs, необходимые для алгоритмов.

Обновление для С++ 11:

Начиная с С++ 11, новый std::bind не нуждается в каких-либо typedefs, поэтому они в некотором смысле устарели.

Ответ 2

В основном, они обеспечивают все typedef, необходимые для создания композиции функций более высокого порядка из унарных и двоичных функций с использованием функциональных адаптеров. Например, это позволяет использовать двоичный функтор, где требуется унарный, привязывая один из аргументов к буквальному значению:

std::find_if( begin, end, std::bind1st(greater<int>(),42) );

std::bind1st полагается на переданный ему функтор для предоставления этих типов.

AFAIK новый std::bind им не нужен, поэтому в новом коде вы можете использовать std::bind и покончить с ними.

Ответ 3

Есть объяснение в документации sgi STL Объекты функции. Таким образом, unary_function и binary_function используются для адаптации функторов. Это позволяет использовать их с адаптерами объектных объектов, такими как unary_negate.

Ответ 4

Каковы они?

std:: unary_function и std:: binary_function являются базовыми структурами для создания адаптируемых функциональных объектов. Слово адаптируемое означает, что они предоставляют необходимые typedef для использования в сочетании со стандартными функциональными адаптерами, такими как 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 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)
);

Как насчет С++ 11 и выше?

Все приведенные выше примеры намеренно используют только С++ 03.

Причина в том, что std:: unary_function и std:: binary_function устарели с С++ 11 и полностью удалены из С++ 17.

Это случилось с появлением более обобщенных и гибких функций, таких как std:: bind, которые наследуют от std:: unary_function и std:: binary_function избыточно.