zoukankan      html  css  js  c++  java
  • 仿函数

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

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

    }

  • 相关阅读:
    常见mysql中出现的问题
    php 根据身份证号相关操作
    Linux的上传文件和下载文件
    php实现socket
    PHP开启缓存加速
    spark使用Hive表操作
    部署ganglia3.7
    Redis Cluster架构优化
    spark读取hdfs数据本地性异常
    spark join broadcast优化
  • 原文地址:https://www.cnblogs.com/lverson/p/3164037.html
Copyright © 2011-2022 走看看