#include<iostream>
#include<list>
#include<algorithm>
#include<functional>
using namespace std;
bool isInsteresting(const string* obj)//判断某个类型是否有趣
{
if ((*obj)[4] % 7 == 0)
{
return true;
}
return false;
}
int main()
{
list<string*> listString(20);
for (int i = 0; i < 26; i++)
{
listString.push_back(new string("haha"+(i+'a')));
}
//接下来找到第一个满足isInsteresting的string
list<string*>::iterator i = find_if(listString.begin(), listString.end(), isInsteresting);
if (i != listString.end())
{
//找到满足的条件之后
}
//反之,如果想找到第一个不满足isInterseting条件的string指针,下边的方法显而易见却不能通过编译
//list<string*>::iterator iN = find_if(listString.begin(), listString.end(), not1(isInsteresting));
//正确的方法是,在应用Not1之前,必须加上ptr_fun
list<string*>::iterator iN = find_if(listString.begin(), listString.end(), not1(ptr_fun(isInsteresting)));
if (i != listString.end())
{
//doSomething
}
return 0;
}
为什么加上ptr_fun就能编译运行了呢,问题的答案也许有些出乎意料,ptr_fun只不过完成了一些类型定义的工作,而这些类型定义是Not1所必须的。isInteresting作为一个基本的函数指针,它缺少Not1所需要的类型。
4个标准的函数配接器(not1、not2/bind1st/bind2nd(注:std::bind1st 和 std::bind2nd将二元函数转换为一元函数bind1st和bind2的使用方法详解))都有一些特殊的类型定义,那些非标准的、与STL兼容的配接器通常也是如此。提供了这些必要的类型定义的函数对象称为可配接的函数对象,反之,如果函数对象缺少这些类型对象,则称为不可配接的。
特殊的类型定义是指: argument_type、fist_argument_type、second_argument_type、result_type
除非你要编写自定义的配接器,否则你不需要知道有关这些类型定义的细节。
如果函数子类的operator()只有一个实参,那么它应该从std::unary_function继承,如果函数子类的operator()有两个实参,那么它应该从std::binary_function继承。
由于unary_function和binary_function是STL的模板,所以不能直接继承,相反,必须继承它们所产生的结构,这就要求你指定某些类型实参。对于unary_function,必须指定函数子类operator的参数类型,以及返回类型;对于Binary_function,必须指定三个类型:operator的第一个参数、operator的第二个参数和operator的返回类型。
eg:
template<typename T>
class MeetsThreshold : public unary_function<string, bool>
{
private:
const T threshold;
public:
MeetsThreshold(const T& threshold);
bool operator()(const string&)const;
};
struct WidgeNameCompare :
public binary_function<string, string, bool>{
bool operator()(const string& lhs,const string& rhs) const;
};
注意:传递给unary_function和binary_function的模板参数这是函数子类的operator()的参数类型和返回类型,唯一可能有点奇怪的是,operaror()的返回类型是unary_function和binary_function的最后一个参数。
你可能注意到了MeetsThreshold是一个类,而WidgetNameCompare是一个结构。MeetsThreshold有内部状态(它的阈值数据成员),而类是封装那些信息的合理方法。WidgetNameCompare没有状态,因此不需要任何private的东西。所有东西都是public的仿函数类的作者经常把它们声明为struct而不是class,也许只因为可以避免在基类和operator()函数前面输入“public”。把这样的仿函数声明为class还是struct纯粹是一个个人风格问题。如果你仍然在精炼你的个人风格,想找一些仿效的对象,看看无状态STL自己的仿函数类(比如,less、plus等)一般写为struct。
再来看WidgetNameCompare虽然operator()的参数类型是const string&,但是传递给binary_function的类确实WIdget。一般情况下,传递给unary_function和binary_function的非指针类型需要去掉const和引用&。如果operator()带有指针参数,则规则就不同了,下边是widgetNameCompare含数字的另一个不同的版本
struct WidgeNameCompare :
public binary_function<const string*, const string*, bool>{
bool operator()(const string*, const string*) const;
};
对于以指针为参数或者返回诶性的函数子类,一般的规则是,传给unary_function或者binary_function的类型与opertor()参数和类型完全相同。
//找到最后一个不符合阈值"haha"的对象
list<string*> str1;
list<string*>::reverse_iterator ri = find_if(str1.rbegin(), str1.rend(), not1(MeetsThreshold<string>("haha")));
//找到按照WidgetNameCompare的排序规则,排在s之前的第一个string对象
string s("haha");
list<string*>::iterator ri = find_if(str1.begin(), str1.end(), bind2nd(WidgeNameCompare(), s));
STL是假设每一个函数子类只有一个operator()成员函数,
当然也可以将两个operator()何在一起,但是最好不要这样做,因为这样的函数子 只有一半的配接功能,只有一半配接功能的函数子并不比完全不配接的函数子强多少。