- Rule38:把仿函数类设计为用于值传递
-
Rule39:用纯函数做判断式
一个行为良好的operator()当然是const,但不只如此。它也得是一个纯函数。不要修改内部成员对象的值,否则会出现未定义的情况。要记住纯函数没有状态,良好的operator也没有。判断式和判断式对象的operator()都是没有状态的。 -
Rule40:使用仿函数类可适配
关于仿函数,仿函数类我们主要讲解这一部分。我们看,如下的例子:
我们有如下代码,找到第一个有趣的Widget。
class Widget{
//测试用不需要内容
public:
int id;
Widget(int id)
{
this->id = id;
}
};
bool isInteresting(const Widget* pw)
{
if (pw->id == 2)
{
return true;
}
return false;
}
list<Widget*> lwptrs;
lwptrs.push_back(new Widget(1));
lwptrs.push_back(new Widget(2));
list<Widget*>::iterator it = find_if(lwptrs.begin(),lwptrs.end(),isInteresting);
我们通过这种方法是可以的,这是基于仿函数,其实参数isInteresting这是一个函数指针。
现在如果我想要找第一个指向不有趣的Widget的指针,显而易见的方法却编译失败:
list<Widget*>::iterator it = find_if(lwptrs.begin(),lwptrs.end(),not1(isInteresting));
我们需要对isInteresting应用ptr_fun在应用not1之前。
list<Widget*>::iterator it = find_if(lwptrs.begin(),lwptrs.end(),not1(ptr_fun(isInteresting)));
ptr_fun做的唯一的事是使一些typedef有效。not1需要这些typedef,这就是为什么可以把not1应用于ptr_fun,但不能直接对isInteresting应用not1。因为是第几的函数指针,isInteresting缺乏not1需要的typedef。
四个标准函数适配器(not1,not2,bind1st,bind2nd)都需要存在某些typedef。我们应该使调用简单,我们不需要知道任何关于那些typedef的事情。operator()带一个实参的仿函数类,要继承的结构是std::unary_function。operator()带有两个实参的仿函数类,要继承的结构是std::binary_function。
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;
};
unary_function一元,binary_function二元,模板化的最后一个参数与operator()的返回值相同
MeetsThreshold是一个类,而WidgetNameCompare是一个结构。因为一元MeetsThreshold可以有内部状态值,而类是封装那些信息的合理办法。WidgetNameCompare没有状态,因此不需要任何private东西。
-
Rule41:了解使用ptr_fun,memfun。
我们知道如下调用是合理的。
void test(Widget &w);
vector<Widget> vw;
for_each(vw.begin(),vw.end(),test);
对vw的每个元素调用test方法。
如果test是一个Widget的成员函数,而不是一个非成员函数,像这样。
class Widget{
public:
void test();
};
我们期待这么调用:
for_each(vw.begin(),vw.end(),&Widget::test);
但是,STL期待的调用形式就是使用非成员函数的语法形式调用。
所以mem_fun产生了,他们让成员函数可以那么调用。
template<typename R, typename C> // 用于不带参数的non-const成员函数
mem_fun_t<R,C> // 的mem_fun声明。
mem_fun(R(C::*pmf)()); // C是类,R是被指向
// 的成员函数的返回类型
mem_fun带有一个到成员函数的指针pmf,并返回一个mem_fun_t类型的对象。这是一个仿函数类,容纳成员函数指针并提供一个operator(),它调用指向在传给operator()的对象上的成员函数。
正确使用方法如下:
for_each(lpw.begin(), lpw.end(),
mem_fun(&Widget::test));