C++ 我们需要一元函数和二元函数做什么?
我阅读了关于二进制和一元函数的教程。我理解它们的结构,但我无法想象在哪种情况下我需要这些函数。你能举例说明它们的用法吗C++ 我们需要一元函数和二元函数做什么?,c++,stl,C++,Stl,我阅读了关于二进制和一元函数的教程。我理解它们的结构,但我无法想象在哪种情况下我需要这些函数。你能举例说明它们的用法吗 这些不是函数,而是类(实际上是结构,但并不重要)。当您定义自己的二进制函数与STL算法一起使用时,您可以从这些类派生它们,以便自动获得所有的typedef 例如 struct somefancyunary函数:公共std::一元函数 { 结果运算符()(参数常量&) { ... } }; 现在,您不需要为参数类型、结果类型等手动提供typedef。这些结构就像迭代器结构一样
这些不是函数,而是类(实际上是结构,但并不重要)。当您定义自己的二进制函数与STL算法一起使用时,您可以从这些类派生它们,以便自动获得所有的typedef 例如
struct somefancyunary函数:公共std::一元函数
{
结果运算符()(参数常量&)
{
...
}
};
现在,您不需要为参数类型
、结果类型
等手动提供typedef。这些结构就像迭代器
结构一样,只是为了方便我们,以便重用算法所需的typedef
C++11的更新:
从C++11开始,新的
std::bind
实际上不需要任何typedef,因此在某种程度上已经过时了。基本上,它们提供了所有必要的typedef
来允许使用函数适配器从一元和二元函数对象合成高阶函数。例如,这允许在需要一元数的情况下使用二进制函子,将其中一个参数绑定到文字值:
std::find_if( begin, end, std::bind1st(greater<int>(),42) );
std::find_if(begin,end,std::bind1st(greater(),42));
std::bind1st
依赖于传递给它的函子来提供这些类型
假设新的
std::bind
不需要它们,那么在新代码中似乎可以使用std::bind
并删除它们 关于的sgi STL文档有一个解释。总之,一元函数和二元函数用于使函子具有适应性。这允许它们与功能对象适配器一起使用,例如。它们是什么?
和是创建适应性函数对象的基本结构。单词adaptive意味着它们提供必要的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::size\u t threshold):阈值(threshold){}
bool运算符()(const std::string&instance)const
{
返回值(instance.size()<阈值);
}
私人:
常数std::大小\u t阈值;
};
现在,任务非常简单,可以通过std::remove\u copy\u 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::size\t阈值在某处定义
std::remove_copy_if(一些_strings.begin(),一些_strings.end(),
std::ostream_迭代器(std::cout,“\n”),
长度阈值(阈值)
);
如果要使用相同的函数对象打印所有长度严格小于阈值的字符串,该怎么办
我们能想到的显而易见的解决方案是使用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))
);
// 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)
);
//std::size\t阈值在某处定义
std::remove_copy_if(一些_strings.begin(),一些_strings.end(),
std::ostream_迭代器(std::cout,“\n”),
标准::not1(长度阈值(阈值))
);
事实上,上面的代码不会编译,因为我们的LengthThreshold是不可修改的,并且没有std::not1所需的typedef
为了使其具有适应性,我们需要继承std::一元函数:
类长度阈值:公共标准::一元函数
{
//函数对象的主体保持不变
}
现在,我们的第一个示例非常有效
示例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;
}
};
class LengthThreshold:public std::binary_函数
{
公众:
布尔运算符()(常量std::string&lhs,std::size\u t threshold)常量
{
返回lhs.size()<阈值;
}
};
并使用std::BindSecond函数适配器:
// 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))
);
// 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)
);
//std::size\t阈值在某处定义
std::remove_copy_if(一些_strings.begin(),一些_strings.end(),
std::ostream_迭代器(std::cout,“\n”),
std::bind2nd(LengthThreshold(),threshold)
);
那么C++11及更高版本呢?
<以上所有示例仅有意使用C++ 03。< /P>
原因是:STD::unyAyl函数和STD::Bialayl函数从C++ 11被剔除,完全从C++ 17中删除。
随着更通用、更灵活的函数的出现,这使得从std::一元函数和std::二元函数继承变得多余。操作符(Arg\u t const&)
必须用操作符()替换(Arg\u t const&)
还是我遗漏了什么?