part5:仿函数,仿函数类(一)

  • Post author:
  • Post category:其他


  • 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));    



版权声明:本文为cshilin原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。