40.仿函数类的适配性

(本节内容未能理解,建议结合STL源码剖析阅读,另外,我还是习惯于使用lambda)

问题实例

 
假设现有一个存放widget*的list,以及一个判断式判断widget*指向的对象是否有趣:

1
2
list<Widget*> widgetPtrs;
bool isInteresting(const Widget *pw);

如果我们想要查找第一个有趣的widget,直接调用find_if即可:
1
2
3
4
auto i = find_if(widgetPtrs.begin(), widgetPtrs.end(),isInteresting);
if (i != widgetPtrs.end()) {
...//i指向了目标对象
}

但问题在于,如果我想要找第一个不有趣的Widget,常规写法遭到了编译失败:
1
auto i =find_if(widgetPtrs.begin(), widgetPtrs.end(),not1(isInteresting)); //error

为了保证成功编译与运行,我们必须对判断式使用ptr_fun:
1
auto i = find_if(widgetPtrs.begin(), widgetPtrs.end(),not1(ptr_func(isInteresting)));


ptr_fun与适配性

 
ptr_fun所做的事情就是使一些typedef生效。作为一个低级的函数指针,isInteresting不具备not1所需要的typedef。
四个标准函数适配器(not1,not2,bind1st,bind2nd)都需要存在某些typedef,我们称缺乏typedef的对象不可适配。
这里只提及缺乏typedef但并没有描述那些typedef是什么,这是因为除非你需要设计自己的适配器,否则你都可以通过继承一个base sturct来获得它们接受一个参数的谓词继承unary_function,两个的则是接受binary_function


仿函数模板类

 
unary_functionbinary_function是模板,所以必须要指定模板参数.其继承形式大致如下:

1
2
3
4
5
6
7
8
9
10
11
12
template<typename T>
class MeetsThreshold: public std::unary_function<Widget, bool>{
private:
const T threshold;
public:
MeetsThreshold(const T& threshold);
bool operator()(const Widget&) const;
...
};
struct WidgetNameCompare:public std::binary_function<Widget, Widget, bool>{
bool operator()(const Widget& lhs, const Widget& rhs) const;
};

可以看出,operator()的返回值被作为了最后一个模板参数。
一般来说,我们习惯于把无状态类记为struct(也许是为了少打那个public),有数据的类则记为class.
可以看到,operator()的参数是const Widget,但给模板的参数却是Widget,你只需要记得这么做就好了。但如果是指针,一定要记住const不能少,模板参数必须和实参一样。

如果给了一个仿函数类多种调用形式,那必然会减少可适配性。