仿函数 

       重载了 operator(),像函数一样使用的 类对象,就叫仿函数。是STL算法与容器之间灵活定制操作的核心机制

本质

它是个对象,但重载了 operator(),所以可以像函数一样调用。

相对于普通函数的优势

1.可保持状态:通过构造函数传入参数

2.可内联优化

3.每个仿函数都有独特类型

头文件

<functional> 

<algorithm>      //STL算法头文件

举例

template<class T>
class Add {
public:
    T operator()(T a, T b) {
        return a + b;
    }
};

int main() {
    Add<int>addF;//创建类对象
    //对象作为函数调用
    cout << addF(100, 20) << endl;

    return 0;
}

补充说明

依赖仿函数的参数个数,又分一元仿函数、二元仿函数、三元仿函数

如果仿函数返回bool,又称之为谓词,依据参数个数又分为一元谓词,二元谓词,三元谓词

仿函数是用于容器与算法之间的。

谓词

operator()返回的类型是bool

STL自带的仿函数

1.算数运算

二元仿函数,参数表有两个形参

- 负号 negate

int main() {
	int n = 100;
	auto f = negate<int>();//创建仿函数的类对象
	const int ret =f(n);//对象作函数使用
	cout << ret << endl;

	auto f2 = plus<int>();//加运算仿函数
	cout << f2(1, n) << endl;
	cout << f2(50, n) << endl;

	auto f3 = multiplies<int>();//乘法运算仿函数
	cout << f3(20, 40) << endl;

	auto f4 = divides<int>();//除法仿函数

	auto f5 = modulus<int>();//取余

	auto f6 = minus<int>();//减法

	return 0;
}

2.关系运算

int main() {
	auto f1 = less<>();//小于
	auto f2 = less_equal<>();//小于等于、
	auto f3 = greater<>();//大于
	auto f4 = greater_equal<>();//大于等于
	auto f5 = equal_to<>();//==
	auto f6 = not_equal_to<>();//!=

	cout << f1(11, 25) << endl;//1
	cout << f2(11, 11) << endl;//1
	cout << f3(21, 3) << endl;//1
	cout << f4(21,18 ) << endl;//1
}

3.逻辑运算符仿函数

int main() {
	auto f1 = logical_and<>();//&&逻辑与
	auto f2 = logical_or<>();//||逻辑或
	auto f3 = logical_not<>();//!逻辑非
}

4.位运算仿函数

STL算法

STL算法,基本上都是操作容器的迭代器,外加数据处理的仿函数

头文件

#include<algorithm>

for_each

遍历一个迭代器区间 [first, last),对区间内的每一个元素,执行一次你指定的函数 / 操作。

它不修改容器结构(不增删元素),只负责遍历 + 执行回调。

#include<vector>
#include<list>
#include<map>
#include<set>

template<class T>
void show1(T item) {
	cout << item << " ";
}
int main() {
	vector<int>ns{ 5,2,1,3,4,9,8,7,4,6 };
	for_each(ns.begin(), ns.end(), show1<int>);
	cout << endl;

	list<string>names{ "disen","lucy","Yang Sir","Zhang Sir" };
	for_each(names.begin(), names.end(), show1<string>);
	cout << endl;

	return 0;
}
//任务:自定义for_each算法
template <class Itr,class F>
void forEach(Itr begin, Itr end, F callback) {
	while (begin != end) {
		callback(*begin);
		begin++;
	}
}

all_of   any_of

all_of:逻辑:一处不满足,直接返回 false

any_of:逻辑:一处满足,直接返回 true

bool funcl(int item) {
	return item > 5;
}

int main() {
	vector<int>ns{ 5,2,1,3,4,9,8,7,4,6 };
	
	//al1_of 容器中每一个元素都满足条件 func1返回的结果都为true
	bool ret1=all_of(ns.begin(), ns.end(), funcl);
	cout << ret1 << endl;//0
	
	//any of 容器中任一个元素满足条件,则返回true
	bool ret2 = any_of(ns.begin(), ns.end(), funcl);
	cout << ret1 << endl;//0
	
	return 0;
}

search

在一个序列中查找另一个子序列第一次出现的位置

count

统计区间内等于目标值的元素个数

auto ret3 = count(ns.begin(), ns.end(), 4);
cout << "4元素的个数:" << ret3 << endl;

list<int>ns2(ns.begin(), ns.end());
ret3 = count(ns.begin(), ns.end(), 9);
cout << "9元素的个数:" << ret3 << endl;

count_if

    //统计大于5 的个数
    ret3 = count_if(ns2.begin(), ns2.end(), funcl);
    cout << "大于5的个数:" << ret3 << endl;

复制与交换

copy

将源区间 [first,last) 元素拷贝到目标迭代器起始位置

copy(v.begin(), v.begin() + 3, v2.begin());
cout << "v2 size:" << v2.size() << endl;
for_each(v2.begin(), v2.end(), show);
cout << endl;

copy_if

筛选满足条件的元素,拷贝到目标区间

swap

交换

swap_ranges

交换两个等长区间元素

transform

遍历容器,对每个元素做转换 / 处理,把结果放到目标容器

  • for_each:只执行操作,不赋值、不生成新容器
  • transform:执行转换,把结果写入新容器

replace

遍历区间,把等于 old_val 的元素,全部替换成 new_val 等值替换

replace_if 条件替换

满足条件就替换

STL 移除 / 填充类算法

fill

给容器指定范围的所有元素,统一填充同一个固定值。

generate

给容器指定范围的元素,通过调用自定义函数动态生成,支持随机数、序列等可变内容。

移除类算法:remove /remove_if/unique

        把需要保留的元素向前移动,把要删除的元素移到容器末尾,最终返回第一个待删除元素的迭代器。

remove

移除容器中等于指定值的所有元素。

将删除的元素移动到尾部,并返回删除元素的开始位置。

删除操作删除元素的内容,空间还在,只是排列到后面去了,空间内容是尾部数据的替换

remove_if

移除容器中满足自定义条件的所有元素,灵活性远高于remove

unique

移除容器中相邻的重复元素,只保留第一个。

复制 + 移除类算法:remove_copy /remove_copy_if

        和remove/remove_if逻辑一致,但不会修改原容器,而是把保留的元素,复制到一个新的目标容器中。

lambda表达式

定义

生成一个匿名函数

语法

[局部变量捕获列表](参数表)->返回类型{ }

[ ] 空,函数体内不访问外部局部变量

[=] 值,函数体可以访问外部的局部变量,但是只读。如果要修改,必须声明mutable

[&] 引用,函数体内访问外部变量,以引入的方式

[a] 单变量 值,函数体内只能访问 a 局部变量

[a,b] 多变量 值,函数体内只能访问a,b局部变量

[&a] 单变量引用

[&a,&b] 多变量引用

[a,&b] a是值,b是引用

[&,a] a是值,其他的局部变量是引用方式捕获

[=,&a] a是引用,其他的局部变量是值

最简短的lambda表达式

1.[ ]{ }

2.[=]()mutable{ }

捕获列表

引入局部变量的方式

=值引入 ,创建副本,默认只读,如果要改内容时,加mutable

&引用 

变量名 ,... 默认值引入

&变量名, 引用方式

变量名,&变量  组合方式

mutable

=值得方式捕获时,创建局部变量的副本,默认副本是只读的。

这个关键字可以修改副本。

int main() {
    int x = 1, y = 5;
    //f是lambda表达式 名称
    //f 也是函数名
    auto f = [=](int a)mutable->int {
        //=值得方式捕获时,默认副本是只读的
        x++;
        y += 5;
        cout << "lambda:" << x << "," << y << endl;
        return (x + y) * a;
    };
    return 0;
}

=值捕获时,表达式内部修改变量值,不影响外部的变量

&引用,局部变量在块中是引用的方式使用,内外是同步的。

删除拷贝

remove_copy

复制非指定值到新容器

跳过v中指定元素(要删除),其他元素复制到v2。

remove_copy_if

复制不满足条件的元素到新容器

更多推荐