C + + STL Basics and Applications (7) function object (functor)

Source: Internet
Author: User

To use function as object is a new thinking of program design. STL implements function object function by overloading the operator () function in the class, not only can carry on the various operation to the data in the container, but also can maintain own state. As a result, function objects are more generic than standard C library functions.

This chapter introduces the use of function pointers, the definition of function objects, the purpose of introduction, the use of the STL built-in function objects under the C++98 Standard and c++11 standards, and the use of adapter classes. Includes the use of bind1st bind2nd not1 not2 mem_fun mem_fun_ref ptr_fun bind ref cref. function PointersA function pointer is a pointer to a function variable, and when the program compiles, each function has an entry address, and the function pointer to the function points to the address. function pointers are primarily used for the following two purposes: calling a function and using it as a function parameter.

Declaring methods for function pointers
Data type identifier (pointer variable name) (parameter list);
The Declaration of a general function is:
int func (int x);
A function pointer is declared as follows:
Int (*func) (int x);
The parentheses (*func) are necessary to tell the compiler that a function pointer is declared instead of a function with a return type of pointer, and if no parentheses, int* func (int x) becomes a func (int x) function that returns a value of int *; The subsequent formal parameters are based on the function parameters. The function address can be obtained from the function name or the function name, as shown in the following example:

#include <iostream>using namespace Std;int Add (int x,int y) {return x+y;} int main () {int (*f) (int x,int y);    Declares a function pointer f=add;    function pointer assignment//can also be written as: f=&add;cout<<f;    Call return 0 like a normal function;}
Why a Function object is introducedFirst look at the following code, using the For_each algorithm to find the sum of the integers stored in the vector:
#include <iostream> #include <vector> #include <algorithm>using namespace std;int sum=0;void f (int x) { Sum+=x;} int main () {vector<int> v;for (int i=0;i<100;i++) {v.push_back (i);} For_each (V.begin (), V.end (), f); Cout<<sum;return 0;}
The For_each () function is defined in <algorithm>, the first two parameters are bounded iterators, the last parameter is a function pointer, and For_each () executes the function pointed to by the third argument, taking a value as the parameter each time the iterator bounds. In this example, the value x is taken from V.begin (), followed by F (x), until V.end (). Notice that, in order to implement this summation function, a sum global variable is used, and f (int) is a global function. With the popularization and development of C + + object-oriented thought, most of the functions are encapsulated in the class, which realizes modularization programming. Then the above functions will be encapsulated in the following form:
Class Sum{private:int Sum;public:sum () {sum=0;} void f (int x) {sum+=x;} int Getsum () {return sum;}};
with encapsulation, how is it convenient to invoke the Sum::f () method? By the way, how do you invoke the required function in the desired class? This is a very critical issue. The use of Function objects provides a quick introduction to functions that quickly use objects in the desired class.
what is a function object (also called an imitation function)a function object is an instance of a class that overloads the operator (), and operator () is a function call operator. A simple example of a function object is as follows:
Class Sum{private:int Sum;public:sum () {sum=0;} void operator () (int x) {sum+=x;} int Getsum () {return sum;}};
Note that the difference from the previous is that the operator () is overloaded instead of the F () function.

Use the function object to implement the For_each algorithm to save the sum of integers in the vector:
#include <iostream> #include <vector> #include <algorithm>using namespace Std;class sum{private:int Sum;public:sum () {sum=0;} void operator () (int x) {sum+=x;} int Getsum () {return sum;}}; int main () {vector<int> v;for (int i=0;i<100;i++) {v.push_back (i);} Sum S=for_each (V.begin (), V.end (), sum ()); Cout<<s.getsum (); return 0;}
the Sum s is used at this time to receive the final result returned by For_each (). The STL defines a number of function objects for programmers to use, including a large number of algorithms, which are described in detail later in this article.

Function Object Classification The standard C + + library classifies function objects according to the number of operator () parameters of 0, one, and 2. There are 5 main types of the following:
Generator: A function object that has no parameters and returns an arbitrary type value, such as a random number generator.
unary function: A parameter of only one type and returns a function object that may have different types of values.
A binary function: A parameter that has two arbitrary types and returns a function object that may have different types of values.
Unary decision function: Returns a unary function of type bool.
Binary decision function: Returns the two-tuple function of the bool type.

As you can see, the function object in STL is only applicable to two parameters, but this is enough to accomplish quite powerful function, when using STL function object, header file <function> is required.

C++98 Standard and C++11 standard for the use of function objects have a big change, the following will explain the difference between the two and use, here I recommend the use of the C++11 standard function object. See the links at the bottom of this article to learn more about the two children's shoes.

c++98 the use of function objects in the standardUnary functions The unary function base class in STL is a template class whose prototype is as follows:
Template<class _arg,class _result>struct unary_function{typedef _result result_type;};
Two template parameters, _arg is the input parameter type, and _result is the return type.
two-tuple functionthe two-tuple function base class in STL is also a template class, and its prototype is as follows:
Template<class _arg1,class _arg2,class _result>struct binary_function{typedef _Arg1 first_argument_type; typedef _arg2 SECOND_ARGUMENT_TYPE;TYPEDEF _result result_type;};
Although a user-defined function object can be compiled and used correctly, it is best to inherit one of these, because for the successor, the STL can extend it two times, for example, it can be encapsulated again using a function adapter, and its own function object lacks extensibility.
Use the two-tuple function to arrange the output instance in ascending order of student grades:
#include <functional> #include <iostream> #include <string> #include <vector> #include < Algorithm> #include <iterator>using namespace Std;class student{private:string name;int grade;public:student (String Name,int grade) {This->name=name;this->grade=grade;} Friend ostream& operator << (ostream& o,const student& s) {cout<<s.name<< "\ T" << S.grade<<endl;return o;} BOOL operator < (const student& s) Const{return This->grade < S.grade;}}; Template <class _arg1,class _arg2>class binary_sort:public binary_function<_arg1,_arg2,bool>{public: BOOL Operator () (_ARG1 a1,_arg2 A2) {return a1 < A2;}}; int main () {vector<student> V;v.push_back (Student ("Qin Shihuang"), V.push_back (Student ("Kangxi"); V.push_back (    Student ("Li Shimin"); Sort (V.begin (), V.end (), Binary_sort<const student&,const student&> ());    Use the two-tuple function to sort copy (V.begin (), V.end (),ostream_iterator<student> (cout)); Output return 0;}
Output:
Kangxi 60
Qin Shihuang 80
Li Shimin 90

system function object: STL provides some of the built-in function objects, divided into arithmetic classes, relational operations classes, and logical operations classes, as described below.
STL standard Function Object table:

The following shows the usage of plus<t>, which other readers can explore in their own analogy:
#include <functional> #include <iostream> #include <vector> #include <numeric>using namespace    Std;class Complex{private:float R;    Real part of float V; Imaginary part Public:complex () {this->r=0.0f;this->v=0.0f;}    Complex (float R,float v) {this->r=r;this->v=v;} Friend ostream& operator << (ostream& o,const complex& c) {cout<<c.r<< "+" <<c.v< < "I" <<endl;return o; Complex operator + (const complex& c) Const{complex temp (THIS-&GT;R+C.R,THIS-&GT;V+C.V); return temp;}}; int main () {//two complex numbers add complex C1 (n); Complex C2 (2,2); Complex rusult1=plus<complex> () (C1,C2); cout<<rusult1;//Several complex numbers accumulate Complex C3 (3,3); Complex C4 (bis); Complex c5 (5,5); vector <Complex> V;v.push_back (C1); V.push_back (C2); V.push_back (C3); V.push_back (C4); v.push_ Back (C5); Complex C; Complex result2=accumulate (V.begin (), V.end (),c,plus<complex> ()); Cout<<result2;return 0;}
Output:
3+3i
15+15i

Accumulate () is a cumulative numeric function, which is described in a later section.
It can be found that when only two complex numbers are added, the use of built-in function objects is not convenient, rather than directly with the Complex C=C1+C2 convenient, but when it is combined with the STL algorithm, its advantages are embodied, such as the program to accumulate 5 complex numbers, if it is 100, 10,000? So looking at the STL's data structure alone may feel bloated, but when combined with the STL algorithm, it will be unstoppable. function Adapter bind1st bind2nd not1 not2 mem_fun mem_fun_ref ptr_fun As the name implies, a function adapter can transform a function (function object) into another function (function object) that functions roughly. Just like the power adapter in life, turning a three-port socket into a two-port socket via the power adaptor is easy to use. For example, if you want to calculate the number of less than 4 in an array of int a[], you would use the less<int> () function, but how do you represent the 4 you want to compare? This time with the function adapter can be very good solution. In addition, most of the algorithms in STL are implemented by invoking the overloaded operator () operator in the function class, but there are many common member functions in the function class, and the STL itself cannot be called directly, and it needs to be transformed by the function adapter before it can be called.

c++98 function Adapter Classification table:
The function adapter uses the following:
#include <functional> #include <iostream> #include <algorithm> #include <iterator> #include <string> #include <vector>using namespace Std;class student{private:string name;int number;public:student (String name,int number) {This->name=name;this->number=number;} BOOL Show () {cout<<endl<< "Name:" <<name<< "\tnumber:" <<number;return true;}; BOOL F (int a) {return a>7;} BOOL g (int A,int b) {return a>b;} int main () {int A[]={10,9,8,7,6,5,4,3,2,1};int n1=count_if (a,a+sizeof (a)/sizeof (int), bind1st (Less<int> (), 4)) ; int n2=count_if (A,a+sizeof (a)/sizeof (int), bind2nd (Less<int> (), 4)); int n3=count_if (A,a+sizeof (a)/sizeof ( int), NOT1 (bind2nd (less<int> (), 4)), Sort (a,a+sizeof (a)/sizeof (int), Not2 (Less<int> ())), copy (a,a+ sizeof (a)/sizeof (int),ostream_iterator<int> (cout, "")); int n4=count_if (A,a+sizeof (a)/sizeof (int), Ptr_fun (f ); int n5=count_if (A,a+sizeof (a)/sizeof (int), bind2nd (Ptr_fun (g), 8)); Student S1 ("Qin Shihuang", 1001); studENT S2 ("Qianlong", 1002);vector<student> V1;v1.push_back (S1); V1.push_back (S2); Vector<student *> V2;v2.push_ Back (&AMP;S1); V2.push_back (&AMP;S2); For_each (V1.begin (), V1.end (), Mem_fun_ref (&student::show)); For_each ( V2.begin (), V2.end (), Mem_fun (&student::show));cout<<endl<< "n1=" <<n1<< "n2=" << n2<< "n3=" <<n3<< "n4=" <<n4<< "n5=" <<n5<<endl;return 0;}
Output:
10 9 8 7 6 5 4 3 2 1
Name: Qin Shihuang number:1001
Name: Qianlong number:1002
N1=6 n2=3 n3=7 n4=3 n5=2

The procedure is explained as follows:
(1) the less<int> () prototype is:
Template<class _ty>
struct Less:public binary_function<_ty, _ty, bool>
{
BOOL Operator () (const _ty& _left, const _ty& _right) const
{
Return (_left < _right);
}
};
That is, the function compares two parameters and returns true if the first argument is less than the second argument. bind1st (Less<int> (), 4)) binds the first parameter of the less<int> () function to 4, adapting it to a new function, and the count_if () function passes an iterator-scoped element into the new function and the count returns several True, so the meaning of the line statement is the number of elements in the count array than 4, 5~10 altogether 6 numbers, so n1=6.
(2) bind2nd (Less<int> (), 4)) is the second parameter of less<int> () is bound to 4, then the line statement is actually counted less than 4, so n2=3.
(3) Not1 () to the unary function result (return True to false, reverse), so N3 is greater than or equal to 4 of the number of elements, n3=7.
(4) Not2 () is reversed for the result of a two-tuple function, so sort (a,a+sizeof (a)/sizeof (int), Not2 (Less<int> ())) is sorted from large to small.
(5) Ptr_fun () is a normal function adapter, so that a common functions can be called by the STL function, algorithm. bind2nd (Ptr_fun (g), 8) in the code is an error if written in bind2nd (g,8)), because the STL does not accept functions that are not converted by the Ptr_fun ().
(6) Mem_fun_ref, Mem_fun is the member function adapter of the class, the difference is: if the set is based on the object, the shape of the Vector<stunent&gt, then the Mem_fun_ref, if the set is based on the object pointer, like a vector <student *>, then with Men_fun.
Note that you need to add the "&" symbol to the member function address to not omit, the code is near the last two lines For_each () (&student::show) written (student::show) the compiler will error.

c++11 the use of function objects in the standardc++11 function Adapter table:

The system function object, MEM_FN () is similar to Mem_fun (), and Not1 ()/not2 () is similar to c++98 () not1 () in the/not2 standard and is no longer mentioned.

functionWe know that in C + +, callable entities mainly include functions, function pointers, function references, which can be implicitly converted to the object specified by the function, or an object (that is, a function object) that implements the Opetator (). In C++11, a new Std::function object is added, and the Std::function object is a type-safe package for existing callable entities in C + + (we know that such callable entities as function pointers are unsafe types).
bind () c++98, there are two functions bind1st () and bind2nd (), which can be used to bind the first and second parameters of a function object, each of which can bind only one parameter. Various restrictions make the availability of bind1st () and bind2nd () significantly lower. C++11, provides the Std::bind (), it binds the number of parameters is unrestricted, the specific parameters of the binding is not limited, by the user specified, this bind () is the real meaning of the binding, with it, bind1st () and bind2nd () there is no use, Therefore, it is not recommended to use bind1st () and bind2nd () in c++11.

Function/bind () Use the following:
#include <iostream> #include <functional>using namespace std;int myminus (int x,int y) {return x-y;} Class Mynum{private:int A,b;public:mynum () {a=4;b=5;} MyNum (int a,int b) {this->a=a;this->b=b;} int Add () {return a+b;} int Cal (int c,int d) {return a+b+c+d;}}; int main () {function<int (Int,int) > F1=bind (myminus,placeholders::_1,placeholders::_2); int r1=f1 (3,2); cout <<r1<<endl;function<int (int) > F2=bind (myminus,placeholders::_1,4); int r2=f2 (7); cout<<r2 <<endl;function<int () > F3=bind (myminus,7,5); int r3=f3 (); Cout<<r3<<endl;function<int ( Int,int) > F4=bind (myminus,placeholders::_2,placeholders::_1); int R4=f4 (7,4);cout<<r4<<endl; MyNum num5;function<int () > F5=bind (&AMP;MYNUM::ADD,NUM5); int R5=f5 ();cout<<r5<<endl; MyNum num6 (3,4) function<int (mynum&) > F6=bind (&mynum::add,placeholders::_1); int R6=f6 (NUM6); cout <<r6<<endl; MyNum Num7, Function<int (mynum&,int,int) > f7=Bind (&mynum::cal,placeholders::_1,placeholders::_2,placeholders::_3); int R7=f7 (num7,3,4);cout<<r7< <endl;return 0;}
Output:
1
3
2
-3
9
7
10

The procedure is explained as follows:
(1) Placeholders is a noun space, itself is also located in the noun space STD, std::p laceholders::_1 represents a parameter placeholder, bind (myminus,placeholders::_1,placeholders: _2) indicates that the appropriate function has two parameters, the first parameter corresponds to the first parameter of the original function, the second parameter corresponds to the second parameter of the original function, and bind (myminus,placeholders::_1,4) indicates that the function has only one parameter, The first parameter corresponds to the first argument of the original function, and the second parameter is bound to 4. Bind (Myminus,placeholders::_2,placeholders::_1) is obviously that the function after the adaptation has two parameters, the first parameter corresponds to the second parameter of the original function, the second argument corresponds to the first parameter of the original function.
(2) After a function is fitted, it is to be received by a function object, such as Function<int (Int,int), which represents a functional object constructed with a shape such as an int (int,int), which is worth mentioning , If for simplicity, you can use the Auto keyword to do the type deduction, such as the main function of the first sentence can be replaced with the following sentence equivalent: Auto F1=bind (myminus,placeholders::_1,placeholders::_2); The following statements can all be used with auto. But using auto may create a barrier to code reading, and a person's preference.
(3) In the case of an adaptive class member function, the first parameter of the bind () function is an object of that class, and it needs to be passed directly to the object if the parameter placeholder is not used. A closer look at the use of F6 and F7 can be understood.

ref ()/cref ()These two functions are used to bind parameters as references, where ref () binds the parameter to a normal reference, CREF () binds the parameter to a const reference, and looks directly at the following instance:
#include <iostream>     #include <functional>   using namespace std;void f (int &a,int &b,const int &c) {cout<< "Run function:" <<a<< "\ T" <<b<< "\ T" <<C<<ENDL;++A;++B;//++C;} int main () {int A=1,b=2,c=3;auto fun = bind (F,a,ref (b), cref (c));a=6;b=7;c=8;cout<< "Before running function:" <<a<< "\ T "<<b<<" \ T "<<c<<endl;fun ();cout<<" After running the function: "<<a<<" \ T "<<b<<" \ T "<<c<<endl;return 0;}
Output:
Before running the function: 6 7 8
Running function: 1 7 8
After running the function: 6 8 8

Program Explanation:
(1) A is an int, in the bin () is a value, so the input f () in the actual operation is a copy of the reference, so in "function run" output is changed copy value: 1, instead of real a, the real a has been 6.
(2) b is an int, ref (b) is a reference to B, bind () takes this as a parameter, so when the "run in function" outputs a true B instead of a copy, and F () can also change the value of B, so the last B + + operation becomes 8.
(3) c is an int, cref (c) is a const reference to C, that is, the const int& type, therefore cannot be changed, there is a sentence in the program//++c, if the comment is removed the compiler will error, because + + tries to change a const value.
about the C++98/c++11 function object related content detailed description:http://www.cplusplus.com/reference/functional/

C + + STL Basics and Applications (7) function object (functor)

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.