我们需要unary_function和binary_function做什么?

时间:2010-11-17 11:01:09

标签: c++ stl

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

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

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

4 个答案:

答案 0 :(得分:13)

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

E.g。

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,因此在某种程度上已经过时了。

答案 1 :(得分:7)

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

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

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

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

答案 2 :(得分:6)

有关Function Objects的sgi STL文档的解释。总之,unary_function和binary_function用于制作仿函数 adaptable 。这允许它们与函数对象适配器一起使用,例如unary_negate

答案 3 :(得分:3)

他们是什么?

std::unary_functionstd::binary_function是用于创建自适应函数对象的基础结构。单词 adaptable 意味着它们提供必要的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 不具有适应性,并且没有 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

原因是自 C ++ 11 以来 std :: unary_function std :: binary_function 已被弃用,并且已完全从 C ++中删除17

随着更为通用和灵活的函数(如std::bind)的出现,它们继承自 std :: unary_function std :: binary_function 。 / p>