仿函数

仿函数与一般函数的优势:

         1、仿函数是“smart functions”(智能型函数)

                仿函数可以拥有成员函数和成员变量,即仿函数拥有状态。

         2、每个仿函数都有自己的型别

                每个仿函数有自己的型别。因此,可以将仿函数的型别当做template参数来传递。

          从而指定某种行为模式。

         3、仿函数通常比一般函数速度快

                就template概念而言,由于更多细节在编译期间就已确定,所以通常可能进行更好

          的最佳化。所以,传入一个仿函数,可能获得更好的性能。

 

          一、  针对“仿函数拥有属于自己的独特型别”的例子:    

class Person
{
public:
    std::string getFirstName() const
    {
        return firstName;
    }
    std::string getLastName() const
    {
        return lastName;
    }
private:
    std::string firstName;
    std::string lastName;
};

class PersonSortCriterion
{
public:
    bool operator()(const Person& p1, const Person& p2)
    {
        return p1.getLastName() < p2.getLastName() || (!(p1.getLastName() < p2.getLastName()) && (p1.getFirstName() < p2.getFirstName()));
    }
}

          int main()

          {

                 typedef std::set<Person,PersonSortCriterion> PersonSet;
                 PersonSet coll;

          }

          这里coll使用了特殊排序准则PersonSortCriterion,而它是个仿函数类别,所以可以把

    它当做set的template参数。以上述型别作为排序准则的所有sets,都拥有自己的独特型别

  (PersonSet)。

          二、拥有内部状态的仿函数。

    class IntSequence
    {
    public:
        IntSequence(int initialValue):value(initialValue) {}
        int operator() ()
        {
            return ++value;
        }
    private:
        int value;
    };

  此仿函数拥有内部变量value,称之为IntSequence的内部状态,利用generate算法生成容器内元素时,可发现value的值是变化的。

  

  三、仿函数一般是传值,不是传引用。因此算法不会改变随参数而来的仿函数的状态。

  传值的好处:

    你可以传递常量和暂时表达式。

  但有时候我们需要知道仿函数的状态时,可通过两个办法解决:
  1、以by reference的方式传递仿函数。

    需要在调用算法时,明白标示仿函数型别是个reference型别。

    PS:generate_n<back_inserter_iterator<list<int> >, int, IntSequence&>(back_inserter(coll), 4, seq);

  2、用for_each的返回值。

    for_each的返回值是仿函数。

  

  四、remove_if算法的问题:

  实作代码:

  template<class ForwIter, class Predicate >

  ForeIter std::remove_if(ForwIter beg, ForwIter end, Predicate op)

  {

    beg = find_if(beg, end,op);

    if(beg == end)

    {

      return beg;

    }

    else

    {

      ForwIter next = beg;

      return remove_copy_if(++next, end,beg,op);

    }

  }

  该算法,使用find_if来搜寻第一个元素。然而接下来它使用传进来的判断是op的副本去处理剩余元素。在移除元素的过程中会出现意想不到的错误。

 

   五、函数配接器:

  bind1st,bind2st,not1,not2(!op(param1,param2))

  针对成员函数设计的函数配接器:

  mem_fun_ref(op)  :调用op,那是某对象的一个const成员函数。

  mem_fun(op)    :调用op,那是某对象指针的一个const成员函数。

  Note:被mem_fun_ref和mem_fun调用的成员函数必须是const,C++标准程序库并不针对non-const成员函数提供函数配接器。

  针对一般函数:

  prt_fun(op)。

  

  六、自定义仿函数也使用函数配接器。

  你可以编写自己的仿函数,但要求它能够使用函数配接器,就必须满足某些条件:必须提供一些型别成员来反映其参数和返回值的型别。

   PS:

  template <class T1, class T2 >
  class fopow:public std::binary_function<T1, T2 ,T1>
  {  
  public:
     T1 operator()(T1 base, T2 exp) const
     {
        return std::pow(base,exp);
     }
  };

  main中的使用:

  std::vector<int> coll2;
   for(int i = 0; i<= 9; ++i)
   {
      coll2.push_back(i);
   }
   std::transform(coll2.begin(),coll2.end(),std::ostream_iterator<int>(std::cout,"  "),std::bind1st(fopow<float,int>(),3));
   std::transform(coll2.begin(),coll2.end(),std::ostream_iterator<int>(std::cout," s "),std::bind2nd(fopow<float,int>(),3));
 

  七、组合函数配接器

  1、op1(op2(x))

  实现:

template<class OP1, class OP2>

class compose_f_gx_t : public std::unary_function<typename OP2::argument_type, typename OP1::result_type>

{

public:  

  compose_f_gx_t(const OP1& o1, const OP2& o2) : op1(o1),op2(o2){}  

  typename OP1::result_type operator()(const typename OP2::argument_type& x) const  

  {   

    return op1(op2(x));  

  }

private:  

  OP1 op1;  OP2 op2;

};

template <class OP1, class OP2>

inline compose_f_gx_t<OP1,OP2> compose_f_gx(const OP1& o1, const OP2& o2)

{  

  return compose_f_gx_t<OP1,OP2>(o1,o2);

}

 2、op1(op2(x),op3(x)

实现:

template<class OP1, class OP2, class OP3>

class compose_f_gx_hx_t : public std::unary_function<typename OP2::argument_type, typename OP1::result_type>

{

public:

  compose_f_gx_hx_t(const OP1& o1,const OP2& o2,const OP3& o3):op1(o1),op2(o2),op3(o3){}

  typename OP1::result_type operator() (const typename OP2::argument_type& x) const

  {

    return op1(op2(x),op3(x));

  }

private:
   OP1 op1;
   OP2 op2;
   OP3 op3;

};

template <class OP1, class OP2, class OP3>

inline compose_f_gx_hx_t<OP1,OP2,OP3> compose_f_gx_hx(const OP1& o1, const OP2& o2, const OP3& o3) 

{

return compose_f_gx_hx_t<OP1,OP2,OP3>(o1,o2,o3);
}

3、op1(op2(x),op3(y))

template<class OP1, class OP2, class OP3>

class compose_f_gx_hy_t : public std::binary_function<typename OP2::argument_type, typename OP3::argument_type, typename OP1::result_type>

{

public:  compose_f_gx_hy_t(const OP1& o1, const OP2& o2, const OP3& o3):op1(o1),op2(o2),op3(o3){}  

  typename OP1::result_type operator()(const typename OP2::argument_type& x, const typename OP3::argument_type& y) const  

  {   

    return op1(op2(x),op3(y));  

  }

private:  

  OP1 op1;  

  OP2 op2;  

  OP3 op3;

};

template <class OP1,class OP2,class OP3>

inline compose_f_gx_hy_t<OP1,OP2,OP3> compose_f_gx_hy(const OP1& o1, const OP2& o2, const OP3& o3)

{  

return compose_f_gx_hy_t<OP1,OP2,OP3>(o1,o2,o3);

}

 

posted @ 2013-06-30 22:43  极限游乐园  阅读(642)  评论(0编辑  收藏  举报