Function objects and predicates
STL- Function Objects
function object
Function Object Concept
Concept:
- A class that overloads the function call operator typically has its objects referred to as function objects.
- Function objects behave like function calls when using the overloaded
()and are also called functors.
Essence:
Function objects (functors) are classes, not functions.
Function objects usage
Features:
- Function objects can be called like regular functions, can take parameters, and can return values.
- Function objects go beyond the concept of ordinary functions, as they can have their own state.
- Function objects can be passed as parameters.
Example:
#include <string>
//1、函数对象在使用时,可以像普通函数那样调用, 可以有参数,可以有返回值
class MyAdd
{
public :
int operator()(int v1,int v2)
{
return v1 + v2;
}
};
void test01()
{
MyAdd myAdd;
cout << myAdd(10, 10) << endl;
}
//2、函数对象可以有自己的状态
class MyPrint
{
public:
MyPrint()
{
count = 0;
}
void operator()(string test)
{
cout << test << endl;
count++; //统计使用次数
}
int count; //内部自己的状态
};
void test02()
{
MyPrint myPrint;
myPrint("hello world");
myPrint("hello world");
myPrint("hello world");
cout << "myPrint调用次数为: " << myPrint.count << endl;
}
//3、函数对象可以作为参数传递
void doPrint(MyPrint &mp , string test)
{
mp(test);
}
void test03()
{
MyPrint myPrint;
doPrint(myPrint, "Hello C++");
}
int main() {
//test01();
//test02();
test03();
return 0;
}
Running/Observing the results: After running, the example will print variable values or addresses; address values depend on the runtime environment, so focus on observing the relative positioning and pointer changes of similar objects.
Summary:
- Functor implementations are highly flexible and can be passed as parameters.
predicate
Predicate Concepts
Concept:
- A functor that returns a boolean type is called a predicate.
- If the operator() takes a single parameter, it's known as a unary predicate.
- If the operator() takes two parameters, it is called a binary predicate.
unary predicate
Example:
#include <vector>
#include <algorithm>
//1.一元谓词
struct GreaterFive{
bool operator()(int val) {
return val > 5;
}
};
void test01() {
vector<int> v;
for (int i = 0; i < 10; i++)
{
v.push_back(i);
}
vector<int>::iterator it = find_if(v.begin(), v.end(), GreaterFive());
if (it == v.end()) {
cout << "没找到!" << endl;
}
else {
cout << "找到:" << *it << endl;
}
}
int main() {
test01();
return 0;
}
Running/Observation Results: After running, the corresponding content will be printed according to the output statements. The variable values can be inferred based on the order of initialization, assignment, and function calls.
In summary: a predicate with only one parameter is called a unary predicate.
Binary predicate
Example:
#include <vector>
#include <algorithm>
//二元谓词
class MyCompare
{
public:
bool operator()(int num1, int num2)
{
return num1 > num2;
}
};
void test01()
{
vector<int> v;
v.push_back(10);
v.push_back(40);
v.push_back(20);
v.push_back(30);
v.push_back(50);
//默认从小到大
sort(v.begin(), v.end());
for (vector<int>::iterator it = v.begin(); it != v.end(); it++)
{
cout << *it << " ";
}
cout << endl;
cout << "----------------------------" << endl;
//使用函数对象改变算法策略,排序从大到小
sort(v.begin(), v.end(), MyCompare());
for (vector<int>::iterator it = v.begin(); it != v.end(); it++)
{
cout << *it << " ";
}
cout << endl;
}
int main() {
test01();
return 0;
}
Running/Observation Results: After running, the corresponding content will be printed according to the output statements. The variable values can be inferred based on the order of initialization, assignment, and function calls.
Summary: A predicate with only two parameters is called a binary predicate.
built-in function objects
The Significance of Built-in Function Objects
Concept:
- STL includes some built-in function objects.
Category:
- arithmetic functor
- relation functor
- logic functor
Usage:
- The objects generated by these functors are used exactly the same way as regular functions.
- Using built-in function objects requires including the header file
#include<functional>
arithmetic functor
Description:
- Implement arithmetic operations
- Among them, negate is a unary operation, and the others are binary operations.
Function Prototype:
template<class T> T plus<T>// Addition Functortemplate<class T> T minus<T>//subtraction functortemplate<class T> T multiplies<T>//Multiplication functortemplate<class T> T divides<T>//division functortemplate<class T> T modulus<T>//modulo functiontemplate<class T> T negate<T>//negation functor
Example:
#include <functional>
//negate
void test01()
{
negate<int> n;
cout << n(50) << endl;
}
//plus
void test02()
{
plus<int> p;
cout << p(10, 20) << endl;
}
int main() {
test01();
test02();
return 0;
}
Running/Observation Results: After running, the corresponding content will be printed according to the output statements. The variable values can be inferred based on the order of initialization, assignment, and function calls.
Summary: When using built-in function objects, you need to include the header file #include <functional>
relation functor
Description:
- Implement relationship comparison
Function Prototype:
template<class T> bool equal_to<T>//equalstemplate<class T> bool not_equal_to<T>//not equal totemplate<class T> bool greater<T>//greater thantemplate<class T> bool greater_equal<T>//greater than or equal totemplate<class T> bool less<T>//less thantemplate<class T> bool less_equal<T>//less than or equal to
Example:
#include <functional>
#include <vector>
#include <algorithm>
class MyCompare
{
public:
bool operator()(int v1,int v2)
{
return v1 > v2;
}
};
void test01()
{
vector<int> v;
v.push_back(10);
v.push_back(30);
v.push_back(50);
v.push_back(40);
v.push_back(20);
for (vector<int>::iterator it = v.begin(); it != v.end(); it++) {
cout << *it << " ";
}
cout << endl;
//自己实现仿函数
//sort(v.begin(), v.end(), MyCompare());
//STL内建仿函数 大于仿函数
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();
return 0;
}
Running/Observation Results: After running, the corresponding content will be printed according to the output statements. The variable values can be inferred based on the order of initialization, assignment, and function calls.
Summary: The most commonly used among relational functors is the greater<> than functor.
logic functor
Description:
- Implement logical operations
Function prototype:
template<class T> bool logical_and<T>//Logic ANDtemplate<class T> bool logical_or<T>//logical ORtemplate<class T> bool logical_not<T>//logical NOT
Example:
#include <vector>
#include <functional>
#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;
//逻辑非 将v容器搬运到v2中,并执行逻辑非运算
vector<bool> v2;
v2.resize(v.size());
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();
return 0;
}
Running/Observation Results: After running, the corresponding content will be printed according to the output statements. The variable values can be inferred based on the order of initialization, assignment, and function calls.
Summary: Logic functors are rarely used in practice, so just be aware of them.