C ++ Primer study note _ 53_STL analysis (8): function adapter: bind2nd, mem_fun_ref, function adapter application example

Source: Internet
Author: User
Tags first string modulus

C ++ Primer study note _ 53_STL analysis (8): function adapter: bind2nd, mem_fun_ref, function adapter application example

Review

5. built-in function objects in STL

I. Adapter

1. Three types of adapters:

(1) Container adapter: Used to expand seven basic containers and use basic container extensions to form stacks, queues, and priority queues.

 

(2) iterator adapter: (reverse iterator, insert iterator, IO stream iterator)

 

(3) function adapter: function adapter can combine a function with another function (or a value or a common function.

[1] function adapters for member functions

[2] function adapters for general functions

Ii. Function Adapter

1. Example

# Include
 
  
# Include
  
   
# Include
   
    
Using namespace std; bool is_odd (int n) {return n % 2 = 1;} int main (void) {int a [] = {1, 2, 3, 4, 5}; vector
    
     
V (a, a + 5); cout <count_if (v. begin (), v. end (), is_odd) <endl; // calculates the number of odd-Number elements. // here, bind2nd converts the binary function object modulus into a one-dimensional function object. // Bind2nd (op, value) (param) is equivalent to op (param, value) cout <count_if (v. begin (), v. end (), bind2nd (modulus
     
      
(), 2) <endl; // bind2nd function object or adapter cout <count_if (v. begin (), v. end (), bind1st (modulus
      
        (), 2) <endl; // bind2nd function object or adapter // bind1st (op, value) (param) is equivalent to op (value, param ); cout <count_if (v. begin (), v. end (), bind1st (less
       
         (), 4) <endl; //> 4. Function adapter cout <count_if (v. begin (), v. end (), bind2nd (less
        
          (), 4) <endl; // <4, function adapter return 0 ;}
        
       
      
     
    
   
  
 
Running result: 2. Source Code Analysis

Here, bind2nd converts the binary function object modulus to The unary function object. How is it done? The tracking source code will be known.

First, bind2nd is a template function, as follows:

// TEMPLATE FUNCTION bind2ndtemplate < class _Fn2,         class _Ty > inlinebinder2nd<_Fn2> bind2nd(const _Fn2 &_Func, const _Ty &_Right){    // return a binder2nd functor adapter    typename _Fn2::second_argument_type _Val(_Right);    return (std::binder2nd<_Fn2>(_Func, _Val));}

Set the anonymous object modulus () And 2 are passed in. The returned value is std: binder2nd <_ Fn2> (_ Func, _ Val). It is a template class object.

// TEMPLATE CLASS binder2ndtemplate
 
  class binder2nd    : public unary_function < typename _Fn2::first_argument_type,      typename _Fn2::result_type >{    // functor adapter _Func(left, stored)public:    typedef unary_function < typename _Fn2::first_argument_type,            typename _Fn2::result_type > _Base;    typedef typename _Base::argument_type argument_type;    typedef typename _Base::result_type result_type;    binder2nd(const _Fn2 &_Func,              const typename _Fn2::second_argument_type &_Right)        : op(_Func), value(_Right)    {        // construct from functor and right operand    }    result_type operator()(const argument_type &_Left) const    {        // apply functor to operands        return (op(_Left, value));    }    result_type operator()(argument_type &_Left) const    {        // apply functor to operands        return (op(_Left, value));    }protected:    _Fn2 op;    // the functor to apply    typename _Fn2::second_argument_type value;  // the right operand};
 

That is, during the construction, the op and value members of binder2nd use modulus () And 2 are initialized. Next, let's look at the main code in count_if:

For (; _ First! = _ Last; ++ _ First)

If (_ Pred (* _ First ))

++ _ Count;

* _ First is the container element obtained through traversal. When the _ Pred condition is met, _ Count ++ can be viewed as: std: binder2nd <modulus > (Modulus (), 2) (* _ First) that is, call the operator () function of the binder2nd class, return (op (_ Left, value); that is, modulus () (* _ First, 2); that is, the operator () function of the modulus class is called, as follows:

// TEMPLATE STRUCT modulustemplate
 
  struct modulus        : public binary_function<_Ty, _Ty, _Ty>{    // functor for operator%    _Ty operator()(const _Ty &_Left, const _Ty &_Right) const    {        // apply operator% to operands        return (_Left % _Right);    }};
 
That is, if the left operand is an even number, 0, odd % 2 = 1 is returned, and true is returned. The final conclusion is that count_if calculates the number of elements in the container with an odd number. In short, it can be understood as follows: bind2nd (op, value) (param) is equivalent to op (param, value ); here, param is the element value, and value is the parameter to be bound. The so-called bind2nd is also the meaning of binding the second parameter. Therefore, bind2nd converts the binary function object modulus into a one-dimensional function object, because the second parameter is 2, the first parameter here is the element value of the container obtained through traversal.

Similar to bind2nd, there is also bind1st, which, as the name suggests, means to bind the first parameter. the following expression: count_if (v. begin (), v. end (), bind1st (less (), 4); that is, the number of elements larger than 4 in the computing container. The left operand is bound here.

Iii. Function adapter application example

(1) function adapters for member functions

1. Example

# Include
 
  
# Include
  
   
# Include
   
    
# Include
    
     
Using namespace std; class Person {public: Person (const string & name): name _ (name) {}void Print () const {cout <name _ <endl ;} void PrintWithPrefix (string prefix) const {cout <prefix <name _ <endl;} private: string name _ ;}; void foo (const vector
     
      
& V) {for_each (v. begin (), v. end (), mem_fun_ref (& Person: Print); // mem_fun_ref converts a parameter not included into one dollar for_each (v. begin (), v. end (), bind2nd (mem_fun_ref (& Person: PrintWithPrefix), "person:"); // mem_fun_ref first converts a dollar to a binary value, bind2nd then converts the binary into a dollar} void foo2 (const vector
      
        & V) {for_each (v. begin (), v. end (), mem_fun (& Person: Print); for_each (v. begin (), v. end (), bind2nd (mem_fun (& Person: PrintWithPrefix), "person:") ;}int main (void) {vector
       
         V; // target object v. push_back (Person ("tom"); v. push_back (Person ("jerry"); foo (v); vector
        
          V2; // For pointer v2.push _ back (new Person ("tom"); v2.push _ back (new Person ("jerry"); foo2 (v2 ); return 0 ;}
        
       
      
     
    
   
  
 
Running result: 2. Source Code Analysis

In the foo function, mem_fun_ref In the first line converts a member function without parameters into a mona1 function object. You can track the code by yourself. In fact, it is similar to the above bind2nd, it should be noted that the function pointer is passed:

template < class _Result,         class _Ty > inlineconst_mem_fun_ref_t<_Result, _Ty>mem_fun_ref(_Result (_Ty::*_Pm)() const){    // return a const_mem_fun_ref_t functor adapter    return (std::const_mem_fun_ref_t<_Result, _Ty>(_Pm));}// TEMPLATE CLASS const_mem_fun_ref_ttemplate < class _Result,         class _Ty >class const_mem_fun_ref_t    : public unary_function<_Ty, _Result>{    // functor adapter (*left.*pfunc)(), const *pfuncpublic:    explicit const_mem_fun_ref_t(_Result (_Ty::*_Pm)() const)        : _Pmemfun(_Pm)    {        // construct from pointer    }    _Result operator()(const _Ty &_Left) const    {        // call function        return ((_Left.*_Pmemfun)());    }private:    _Result (_Ty::*_Pmemfun)() const;   // the member function pointer};

 

The input parameter is a function pointer, that is, void (Person: * _ Pm) () const, after passing _ Pm = & Print, in operator () return (_ Left. * _ Pmemfun) (); _ Left is the Person class object that is traversed. Find the class function and call it.

In the second row, mem_fun_ref accepts two parameters, which are obviously overloaded versions. It converts a mona1 function to a binary function object, and bind2nd converts it to a mona1 function object, that is, the second parameter "person:" Is bound. The trace source code can see such a function call:

_Result operator()(_Ty &_Left, _Arg _Right) const{    // call function with operand    return ((_Left.*_Pmemfun)(_Right));}

That is, the second parameter is passed to PrintWithPrefix as a parameter, so the printed person with the prefix is similar to mem_fun, but the result of this for_each traversal is the object pointer, therefore, you need to use the-> operator for function calling, as shown below:

_Result operator()(const _Ty *_Pleft) const{    // call function    return ((_Pleft->*_Pmemfun)());}_Result operator()(const _Ty *_Pleft, _Arg _Right) const{    // call function with operand    return ((_Pleft->*_Pmemfun)(_Right));}

(2) function adapter for general functions: ptr_fun

1. Example 1:

# Include
 
  
# Include
  
   
# Include
   
    
# Include
    
     
Using namespace std; int main (void) {char * a [] = {"", "BBB", "CCC"}; vector
     
      
V (a, a + 2); vector
      
        : Iterator it; it = find_if (v. begin (), v. end (), bind2nd (ptr_fun (strcmp), ""); // check if (it! = V. end () cout <* it <endl; return 0 ;}
      
     
    
   
  
 
Running result:

Ptr_fun converts strcmp binary functions to binary function objects, bind2nd converts them to a one-dimensional function object, that is, the second parameter is bound, because strcmp returns true if the comparison is not equal, therefore, find_if searches for the first string location not equal to the Null String.

Example 2:

#include 
 
  #include #include 
  
   #include 
   
    #include 
    
     using namespace std;bool check(int elem){    return elem < 3;}int main(void){    int a[] = {1, 2, 3, 4, 5};    vector
     
       v(a, a + 5);    vector
      
       ::iterator it; it = find_if(v.begin(), v.end(), not1(ptr_fun(check))); if (it != v.end()) cout << *it << endl; return 0;}
      
     
    
   
  
 
Running result: ptr_fun converts the check mona1 function to a mona1 function object. not1 performs a reverse operation, which turns out to be <3. The reverse operation is> = 3; therefore, find_if searches for the first element location greater than or equal to 3.

The tracking of these codes is left for everyone to complete. Due to the limited space, we cannot show all the calling processes. To learn STL, we still have to follow the source code to gain a deeper understanding.

Refer:

C ++ primer version 4
Valid tive C ++ 3rd
C ++ programming specifications


Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.