我们需要unary_function和binary_function做什么?

发布于 2024-10-03 06:51:13 字数 411 浏览 0 评论 0原文

我阅读了有关二元和一元函数的教程。我理解它们的结构,但我无法想象在什么情况下我需要这些功能。你能举一个使用它们的例子吗?

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

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

I read the tutorials about the binary and unary functions. I understood the structure of them, but I couldn't imagine in which case I need these functions. Can you give an example for usage of them.

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

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

铁憨憨 2024-10-10 06:51:13

这些不是函数,而是类(实际上是结构,但并不重要)。当您定义自己的二进制函数以与 STL 算法一起使用时,您可以从这些类派生它们,以便自动获取所有 typedef。

例如,

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

现在您不需要手动提供 argument_typeresult_type 等的 typedef。这些结构,就像 iterator 结构一样,就在那里为了我们的方便,为了重用算法所需的 typedef。

C++11 更新:

从 C++11 开始,新的 std::bind 并不真正需要任何 typedef,因此在某种程度上,它们已经过时了。

These aren't functions, these are classes (structs, actually, but doesn't matter). When you define your own binary functions to use with STL algorithms, you derive them from these classes in order to automatically get all the typedefs.

E.g.

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

now you don't need to manually provide the typedefs for argument_type, result_type etc. These structs, just like the iterator struct are there just for our convenience, in order to reuse the typedefs needed for algorithms.

Update for C++11:

As of C++11, the new std::bind does not really need any typedefs, so there are, in a way, obsolete.

木格 2024-10-10 06:51:13

基本上,它们提供了允许使用函数适配器从一元和二元函数对象组合高阶函数所需的所有 typedef。例如,这允许在需要一元的情况下使用二进制仿函数,将参数之一绑定到文字值:

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

std::bind1st 依赖于传递给它的仿函数来提供这些类型。

AFAIK 新的 std::bind 不需要它们,因此在新代码中您似乎可以使用 std::bind 并取消它们。

Basically, they provide all the typedefs necessary to allow composition of higher-order functions from unary and binary function objects using function adaptors. For example, this allows using a binary functor where a unary is needed, binding one of the arguments to a literal value:

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

std::bind1st relies on the functor passed to it to provide those types.

AFAIK the new std::bind doesn't need them, so it seems in new code you can use std::bindand do away with them.

扮仙女 2024-10-10 06:51:13

函数对象的sgi STL文档上有一个解释。总之,unary_function 和 binary_function 用于使函子具有适应性。这允许它们与函数对象适配器一起使用,例如 unary_negate

There's an explanation on the sgi STL documentation of Function Objects. In summary, unary_function and binary_function are used to make functors adaptable. This allows them to be used with function object adaptors such as unary_negate.

一曲琵琶半遮面シ 2024-10-10 06:51:13

这些是什么?

std::unary_functionstd::binary_function 是用于创建自适应函数对象的基本结构。 “可适应”一词意味着它们提供了必要的类型定义,以便与标准函数适配器(如 std::not1std::not2std::bind1ststd::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 不具有适应性,并且没有 std::not1 所必需的 typedef。

为了使其具有适应性,我们需要继承 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_functionstd::binary_functionC++ 11 起已弃用,并从 C++ 17 中完全删除嗯>。

它是随着更通用和灵活的函数的出现而发生的,例如 std::bind 使得从 std::unary_functionstd::binary_function 继承变得多余。

What are they?

std::unary_function and std::binary_function are base structs for creation adaptable function objects. The word adaptable means that they provide necessary typedefs for being used in conjunction with standard function adaptors like std::not1, std::not2, std::bind1st, std::bind2nd.

When I need to use them?

You may use them every time you need to use your custom function object together with standard function adaptor.

Do you have an example?

Lets consider some examples (I know, they are artificial. From the other side I hope, that they are rather descriptive).

Example 1.

Suppose you want to print all strings in a vector with their lengths not less than a particular threshold and print them to std::cout.

One might use the next function object:

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;
};

Now the task is pretty simple and can be performed by std::remove_copy_if algorithm:

// 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)
);

What if you want to use the same function object to print all the strings with their lengths strictly less than the threshold?

The obvious solution we can come up with is the usage of std::not1 function adaptor:

// 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))
);

In fact, the code above won't compile because our LengthThreshold is not adaptable and has no typedefs which are necessary for std::not1.

To make it adaptable we need to inherit from std::unary_function:

class LengthThreshold : public std::unary_function<std::string, bool> 
{
    // Function object's body remains the same
}

Now our first example works like a charm.

Example 2.

Lets change our previous example. Suppose we don't want to store a threshold inside the function object. In such case we may change the function object from unary predicate to binary predicate:

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;
        }
};

And make use of std::bind2nd function adaptor:

// 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)
);

What about C++11 and higher?

All the examples above intentionally use only C++ 03.

The reason is that std::unary_function and std::binary_function are deprecated since C++ 11 and completely removed from C++ 17.

It happened with the advent of more generalized and flexible functions like std::bind which make inheriting from std::unary_function and std::binary_function superfluous.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文