今天来到我们STL系列的第九期:仿函数的讲解
什么是仿函数?
仿函数的特点:
STL仿函数的分类:
谓词:
内建的仿函数:
算数仿函数:
关系仿函数:
逻辑仿函数:(不常用)
仿函数作为STL六大组件中的其中一个,也称为函数对象,仿函数是一个能行使函数功能的类,仿函数的语法几乎和普通函数调用一样,不过作为仿函数的类,都必须重载 operator() 运算符。
仿函数的主要功能是为了搭配STL算法使用,单独使用仿函数的情况比较少。
对于他的特点我们分别举例:
仿函数在使用时,可以像普通函数那样调用,可以有返回值
class Mytest {
public:
int operator()(int v1, int v2)
{
return v1 + v2;
}
};
int main()
{
Mytest test01;
cout << test01(1, 2) << endl;
//输出3
return 0;
}
仿函数超出普通函数的概念,可以有自己的状态
class Mytest {
public:
void operator()(string std)
{
cout << std << endl;
this->count++;
}
int count=0;//记录函数调用多少次,内部自己状态
//正常需要定义静态或者全局变量
};
void test02()
{
Mytest test02;
test02("okokok");
test02("okokok");
test02("okokok");
test02("okokok");
cout << test02.count << endl;
//打印4次okokok
}
int main()
{
test02();
return 0;
}
函数对象可以作为参数传递
class Mytest {
public:
void operator()(string std)
{
cout << std << endl;
}
};
void doPrint(Mytest &t,string std)
{
t(std);
}
int main()
{
Mytest t;
doPrint(t, "okfun");
//输出okfun
return 0;
}
以操作数(operand)的个数划分,分为一元和二元仿函数;
以功能划分,可分为算数运算(Arithmetic)、关系运算(Rational)和逻辑运算(Logical);
示例:
一元谓词:利用find_if找到大于5的数字
class Mytest {
public:
bool operator()(int val)
{
return val > 5;
}
};
int main()
{
vector v{1,2,3,4,5,6,7,8,9 };
auto it = find_if(v.begin(), v.end(), Mytest());
if (it == v.end())
{
cout << "没找到" << endl;
}
else
{
cout << "找到了:" << *it << endl;
}
return 0;
}
二元谓词:sort排序,同前几期介绍的自定义规则排序
class Mytest {
public:
bool operator()(int val,int val2)
{
return val>val2;//从大到小排序
}
};
template
void Show(vector &v)
{
for (auto it = v.begin(); it != v.end(); it++)
{
cout << *it << endl;
}
}
int main()
{
vector v{1,2,3,4,5,6,7,8,9 };
sort(v.begin(), v.end(), Mytest());
Show(v);
return 0;
}
STL内部提供了一些仿函数,重载了许多(),便于与STL许多算法搭配使用,使用时我们需要引入头文件#include
template |
加法仿函数 |
template |
减法仿函数 |
template |
乘法仿函数 |
template |
除法仿函数 |
template |
取模仿函数 |
template |
取反仿函数 |
其中只有negate取反为一元运算,其余都为二元运算,下面我会以乘法和取反举例:
void test01()
{
negaten;
cout << n(50.25) << endl;;
}
void test02()
{
multipliesn;//对于二元运算只允许两个数据类型相同,所以只能写一种
cout << n(1.1, 2.5);
}
int main()
{
test01();//输出-50.25
test02();//输出1.1*2.5
return 0;
}
template |
等于 |
template |
不等于 |
template |
大于 |
template |
大于等于 |
template |
小于 |
template |
小于等于 |
我们以大于来举例:
template
void Show(vector &v)
{
for (auto it = v.begin(); it != v.end(); it++)
{
cout << *it << " ";
}
cout << endl;
}
int main()
{
vectorv{ 1,2,3,4,5,6,7,8,9,10 };
Show(v);//
sort(v.begin(), v.end(), greater());//从大到小
Show(v); //等同于上面二元谓词的栗子
return 0;
}
主要实现对比的关系,最常用的为大于,因为默认的排序为小于,我们使用大于关系仿函数可以简单实现上面从大到小的自定义排序,观察sort源码也能发现:
查看sort的声明,STL声明了两种模板
template //需要传入一个_Pr _Pred 自定义的规则
_CONSTEXPR20 void sort(const _RanIt _First, const _RanIt _Last, _Pr _Pred) { // order [_First, _Last)
_Adl_verify_range(_First, _Last);
const auto _UFirst = _Get_unwrapped(_First);
const auto _ULast = _Get_unwrapped(_Last);
_Sort_unchecked(_UFirst, _ULast, _ULast - _UFirst, _Pass_fn(_Pred));
}
template //默认的排序 里面传入的是less<>{} 默认小于
_CONSTEXPR20 void sort(const _RanIt _First, const _RanIt _Last) { // order [_First, _Last)
_STD sort(_First, _Last, less<>{});
}
template |
逻辑与 |
template |
逻辑或 |
template |
逻辑非 |
我们用逻辑非举例:
template
void Show(vector &v)
{
for (auto it = v.begin(); it != v.end(); it++)
{
cout << *it << " ";
}
cout << endl;
}
int main()
{
vectorv{ false,true,true,false };
Show(v);//0 1 1 0
vector v2;
v2要提前开辟大小,不然没有空间存放数据
v2.resize(v.size());
//搬运算法----transform
transform(v.begin(), v.end(), v2.begin(),logical_not());
Show(v2);//1 0 0 1
return 0;
}
对于搬运算法transform,我们查看其源码声明
template
_CONSTEXPR20 _OutIt transform(const _InIt _First, const _InIt _Last, _OutIt _Dest, _Fn _Func)
FIRST对应源容器开始迭代器
LAST 对应源容器结束迭代器
DEST 对应目标容器开始迭代器
Func 对应函数或者函数对象
关于STL中的仿函数我们就到这里了,STL系列也马上结束了,下一期的算法和仿函数经常搭配使用,因此都要好好掌握,有兴趣的可以收藏整个系列,感谢观看!