[C++] Dark Horse C++ Generic Programming and STL Technology (10) STL Function Object

STL function object

    • 4.1 Function objects
    • 4.2 Predicates
      • 4.2.1 Unary predicates
      • 4.2.2 Binary predicates
    • 4.3 Built-in function objects
      • 4.3.1 Arithmetic functors
      • 4.3.2 Relational functors
      • 4.3.3 Logical functors

4.1 Function objects

Objects of classes that overload the function call operator are called function objects. When a function object uses the overloaded (), it acts like a function call, so it is called a functor. Essentially, a function object (functor) is a class, not a function.

Use of function objects:

  1. Function objects can be called like ordinary functions, but they can also have parameters and return values.
  2. Function objects go beyond the concept of ordinary functions, and function objects can have their own state.
  3. Function objects can be passed as arguments

Example:

#include<iostream>
using namespace std;
#include<string>
// 1. Function objects can be called like ordinary functions, but they can also have parameters and return values.
class MyAdd
{<!-- -->
public:
int operator()(int v1, int v2)
{<!-- -->
return v2 + v2;
}
};
void test01()
{<!-- -->
MyAdd myAdd; // myAdd is the function object
cout << myAdd(10,10) << endl;
}
// 2. Function objects are beyond the concept of ordinary functions, and function objects can have their own state.
// For an ordinary function, if you want to count the number of function executions, you need to define a global variable
// The functor can directly define properties in the class to record the number of function executions
class MyPrint
{<!-- -->
public:
MyPrint()
{<!-- -->
this->count = 0;
}
void operator()(string text)
{<!-- -->
cout << text << endl;
this->count + + ;
}
int count; // internal own state
};
void test02()
{<!-- -->
MyPrint myPrint;
myPrint("Hello World!");
myPrint("Hello World!");
myPrint("Hello World!");
cout << "MyPrint calls: " << myPrint.count << endl;
}
// 3. Function objects can be passed as parameters
void doPrint(MyPrint & mp, string text)
{<!-- -->
mp(text);
}
void test03()
{<!-- -->
MyPrint myPrint;
doPrint(myPrint,"Hello!");
}
int main()
{<!-- -->
test01();
test02();
test03();
system("pause");
return 0;
}

4.2 Predicate

A functor that returns a bool type is called a predicate.
If operator() receives one parameter, it is called a unary predicate; if operator() receives two parameters, it is called a binary predicate.

4.2.1 Unary predicates

#include<iostream>
using namespace std;
#include <vector>
#include <algorithm>
class GreaterFive
{<!-- -->
public:
bool operator()(int val)
{<!-- -->
return val>5;
}
};
void test01()
{<!-- -->
vector<int> v;
for(int i = 0;i<10;i ++ )
{<!-- -->
v.push_back(i);
}
// Find if there is a number greater than 5 in the container
vector<int>::iterator it = find_if(v.begin(),v.end(),GreaterFive());
//GreaterFive() is an anonymous object
if(it==v.end())
{<!-- -->
cout << "Not found!" << endl;
}
else
{<!-- -->
cout << "The number greater than 5 found is: " << *it << endl;
}
}
int main()
{<!-- -->
test01();
system("pause");
return 0;
}

A new algorithm find_if is used here, and three parameters need to be passed: the start position and end position (interval) represented by an iterator, and a predicate. Its return value is an iterator, which returns an iterator of the first element that satisfies the condition (the predicate returns true).

4.2.2 Binary predicates

#include<iostream>
using namespace std;
#include <algorithm>
#include <vector>
class myCmp
{<!-- -->
public:
bool operator()(int v1, int v2)
{<!-- -->
return v1>v2;
}
};
void test01()
{<!-- -->
vector<int> v;
v.push_back(5);
v.push_back(2);
v.push_back(4);
v.push_back(3);
v.push_back(1);
//sort
sort(v.begin(),v.end());
for(vector<int>::iterator it = v.begin();it!=v.end();it++ )
{<!-- -->
cout << *it << " ";
}
cout << endl;
// Using the function object, change the sorting rule to descending
sort(v.begin(),v.end(),myCmp());
for(vector<int>::iterator it = v.begin();it!=v.end();it++ )
{<!-- -->
cout << *it << " ";
}
cout << endl;
}
int main()
{<!-- -->
test01();
system("pause");
return 0;
}

operation result:

4.3 Built-in function objects

STL has some built-in function objects (like functions), which can be used directly after including the header file . Built-in function objects can be divided into three categories:
Arithmetic functors, relational functors, logical functors.

4.3.1 Arithmetic functors

Function: Realize four operations
The prototype of the functor is as follows, where negate is a unary operation, and the rest are binary operations.

template<class T> T plus<T> // addition functor
template<class T> T minus<T> // subtraction functor
template<class T> T multiplies<T> // multiplication functor
template<class T> T divides<T> // division functor
template<class T> T modules<T> // take imitation function
template<class T> T negate<T> // negate functor

Example:

#include<iostream>
using namespace std;
#include <functional>
// negate
void test01()
{<!-- -->
negate<int> n;//create function object
cout << n(50) << endl;
}
//plus
void test02()
{<!-- -->
plus<int> p;
// Although two data need to be passed in, only one type declaration is required, because the operation is performed between the same type
cout << p(10,20) << endl;
}
int main()
{<!-- -->
test01();
test02();
system("pause");
return 0;
}

Results of the:

4.3.2 Relational functors

Functor prototype:

template<class T> bool equal_to<T> // equal to
template<class T> bool not_equal_to<T> // not equal to
template<class T> bool greater<T> // greater than
template<class T> bool greater_equal<T> // greater than or equal to
template<class T> bool less<T> // less than
template<class T> bool less_equal<T> // less than or equal to

Example:

#include<iostream>
using namespace std;
#include <vector>
#include<functional> //Include header files
#include <algorithm>
void test01()
{<!-- -->
vector<int> v;
v.push_back(10);
v. push_back(50);
v. push_back(30);
v.push_back(20);
v. push_back(40);
for(vector<int>::iterator it = v.begin();it!=v.end();it++ )
{<!-- -->
cout << *it << " ";
}
cout << endl;
// Sort in descending order using the built-in functor
sort(v.begin(),v.end(),greater<int>());
for(vector<int>::iterator it = v.begin();it!=v.end();it++ )
{<!-- -->
cout << *it << " ";
}
cout << endl;
}
int main()
{<!-- -->
test01();
system("pause");
return 0;
}

4.3.3 Logical functors

(not used much)
Function prototype:

template<class T> bool logic_and<T> // logic and
template<class T> bool logic_or<T> // logical or
template<class T> bool logic_not<T> // logical not

Example:

#include<iostream>
using namespace std;
#include <vector>
#include <algorithm>
void test01()
{<!-- -->
vector<bool> v;
v.push_back(true);
v.push_back(false);
v.push_back(true);
v.push_back(false);
for(vector<bool>::iterator it = v.begin();it!=v.end();it++ )
{<!-- -->
cout << *it << " ";
}
cout << endl;
vector<bool> v2;
v2.resize(v.size());
// There must be space first, and then the transform algorithm can be used
transform(v.begin(),v.end(),v2.begin(),logical_not<bool>());
for(vector<bool>::iterator it = v2.begin();it!=v2.end();it++ )
{<!-- -->
cout << *it << " ";
}
cout << endl;
}
int main()
{<!-- -->
test01();
system("pause");
return 0;
}

operation result: