• STL算法 ——函数对象(仿函数)【仿函数、谓词、内建函数对象、适配器】


    1 函数对象(仿函数)

    #include
    using namespace std;
    
    //函数对象(也叫仿函数 functor)
    //仿函数 通常不需要构造和析构
    class print {
    public:
    	void operator()(string str) {
    		cout << str << endl;
    	}
    };
    void test() {
    	//调用函数对象:方法1
    	print ob;
    	ob("hello world !");
    
    	//调用函数对象:方法2
    	print()("A good day !");
    }
    
    int main() {
    	test();
    
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    函数对象,就是重载小括号;
    类对象和括号结合就会出发函数对象调用;
    在这里插入图片描述

    2 谓词

    返回值为bool类型的普通函数,做谓词
    仿函数,做谓词。

    如果谓词 有一个参数 叫:一元谓词
    如果谓词 有二个参数 叫:二元谓词

    2.1 一元谓词查找案例(两种方式)

    //一元谓词,查找案例
    找到第一个 >30 的元素

    #include
    #include
    using namespace std;
    
    //函数对象(也叫仿函数 functor)
    //仿函数 通常不需要构造和析构
    class print {
    public:
    	void operator()(string str) {
    		cout << str << endl;
    	}
    };
    void test() {
    	//调用函数对象:方法1
    	print ob;
    	ob("hello world !");
    
    	//调用函数对象:方法2
    	print()("A good day !");
    }
    
    //谓词(两种方法,名字一样会报错,稍微区别一下)
    //1.返回值为bool类型的普通函数,做谓词;
    bool greaterThan30(int value) {
    	return  value > 30;
    }
    
    // 2.仿函数,做谓词;
    class greaterThan30 {
    public:
    	bool operator()(int value) const{ //const ;如果调用处错误,需要在此处加const
    		return value > 30;
    	}
    };
    
    void test2() {
    	vector v;
    	v.push_back(10);
    	v.push_back(50);
    	v.push_back(60);
    	v.push_back(30);
    	v.push_back(10);
    
    	//find_it条件查找; 找到满足条件的元素,就返回迭代器
    	vector::iterator ret;
    	//1.普通函数,做谓词; 函数名
    	ret = find_if(v.begin(),v.end(),greaterThan30);
    	// 2.仿函数,做谓词;类名称+()
    	//ret = find_if(v.begin(), v.end(), greaterThan30());
    
    	if (ret != v.end())
    		cout << "找到元素为:" << *ret << endl;
    	else
    		cout << "元素未找到" << endl;
    }
    
    int main() {
    	test2();
    	
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61

    在这里插入图片描述

    返回值为bool类型的普通函数,做谓词;
    调用的时候,只写函数名,不需括号和参数;
    (加括号就成真的函数调用了,这里是谓词,不是函数调用)

    //1.普通函数,做谓词; 函数名
    ret = find_if(v.begin(),v.end(),greaterThan30);
    
    • 1
    • 2

    仿函数,做谓词;
    调用的时候,记得括号

    // 2.仿函数,做谓词;类名称+()
    //ret = find_if(v.begin(), v.end(), greaterThan30());
    
    • 1
    • 2

    在这里插入图片描述

    2.1 二元谓词排序案例(两种方式)

    //二元谓词(两种方法,名字一样会报错,稍微区别一下)
    //1.返回值为bool类型的普通函数,做谓词;
    bool greaterInt(int val1, int val2) {
    	return  val1 < val2;
    }
    
    // 2.仿函数,做谓词;
    class greaterInt2 {
    public:
    	bool operator()(int val1, int val2)const {
    		return val1 < val2;
    	}
    };
    
    void printVector(vector& v) {
    	vector::iterator it = v.begin();
    	for (; it != v.end(); it++)
    		cout << *it << " ";
    	cout << endl;
    }
    void test2() 
    {
    	vector v;
    	v.push_back(10);
    	v.push_back(50);
    	v.push_back(60);
    	v.push_back(30);
    	v.push_back(10);
    
    
    	printVector(v);
    	//sort()排序
    	
    	//1.普通函数,做谓词; 函数名
    	//sort(v.begin(), v.end(), greaterInt);
    	// 2.仿函数,做谓词;类名称+()
    	sort(v.begin(), v.end(), greaterInt2());
    	printVector(v);
    }
    
    int main() {
    	test2();
    
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45

    在这里插入图片描述

    3 内建函数对象

    3.1 排序案例

    //sort(v.begin(), v.end())//默认升序,如想要降序,就要增加排序规则
    //前面自定义谓词函数(1.普通函数 2.仿函数),作为排序规则
    //方法3 使用内置函数对象(仿函数);;;greater();;;大于<数据类型>()
    //内建函数对象,排序

    void test3()
    {
    	vector v;
    	v.push_back(10);
    	v.push_back(50);
    	v.push_back(60);
    	v.push_back(30);
    	v.push_back(10);
    
    
    	printVector(v);
    	//sort()排序
    
    	//sort(v.begin(), v.end())//默认升序,如想要降序,就要增加排序规则
        //前面自定义谓词函数(1.普通函数 2.仿函数),作为排序规则
    	//方法3 使用内置函数对象(仿函数);;;greater();;;大于<数据类型>()
    	sort(v.begin(), v.end(), greater());
    
    	printVector(v);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    在这里插入图片描述

    3.2 查找案例

    //内建函数对象,查找
    void test4() {
    	vector v;
    	v.push_back(10);
    	v.push_back(50);
    	v.push_back(60);
    	v.push_back(30);
    	v.push_back(10);
    
    	find_it条件查找; 找到都一个> value的数,找到满足条件的元素,就返回迭代器
    
    	vector::iterator ret;
    	//1.普通函数,做谓词; 函数名
    	//ret = find_if(v.begin(),v.end(),greaterThan30);
    	// 2.仿函数,做谓词;类名称+()
    	//ret = find_if(v.begin(), v.end(), greaterThan30_());
    	
    	//方法3 内建函数,查找
    	ret = find_if(v.begin(), v.end(),bind2nd(greater(), 30));//适配器bind2nd,头文件
    	//因find_if()只能接受三个参数,内建函数greater(), 30加进来就相当于4参数了,故用适配器将其绑定		
    	if (ret != v.end())
    		cout << "找到元素为:" << *ret << endl;
    	else
    		cout << "元素未找到" << endl;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    4 适配器

    4.1 STL bind1st bind2nd详解

    STL bind1st bind2nd详解

    bind1st、 bind2nd头文件;

    作用:将一个二元算子转换成一个一元算子;
    bind1st是绑定第一个参数,bind2nd则是绑定第二个参数。

    由于二元函数对象接受两个参数,在绑定成为一元函数对象时需要将原来两个参数中的一个绑定下来。

    将二元函数的一个参数绑定为定值,这样二元函数就转换为了一元函数,传进来的参数都相当于是另外一个参数了。

    bind就是绑定的意思,而1st就代表first,2nd就代表second;
    他们的申明是一样的,都是(const Operation& op, const T& x);

    bind1st(const Operation& op, const T& x)就是这么一个操作:x op value,
    bind2nd(const Operation& op, const T& x)就是这么一个操作:value op x,

    其中value是被应用bind的对象。

    例:查找,大于10的元素个数;小于10的元素的个数

    (less(), 10) VS (greater(), 10)
    bind1st VS bind2nd

    (less(), 10)

    void test1() {
    	vector v;
    	for (int i = 1; i <= 10; ++i)
    		v.push_back(i);
    
    	//查找值大于10的元素的个数
    	//也就是使得10 < elem成立的元素个数 
    	int res = count_if(v.begin(), v.end(), bind1st(less(), 10));// x op value,即 10 less elem,10 < elem,大于10的元素
    	cout <<"大于10的元素个数:" <(), 10));// value op x,即 elem less 10,elem < 10,小于10的元素
    	cout << "小于10的元素个数:" << res << endl;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    bind1st(less(), 10);// x op value,即 10 less elem,10 < elem,大于10的元素
    bind2nd(less(), 10);// value op x,即 elem less 10,elem < 10,小于10的元素
    在这里插入图片描述
    (greater(), 10)

    void test2() {
    	vector v;
    	for (int i = 1; i <= 10; ++i)
    		v.push_back(i);
    
    	//查找值大于10的元素的个数
    	int res = count_if(v.begin(), v.end(), bind2nd(greater(), 10));// value op x,即 elem greator 10,elem > 10,大于10的元素
    	cout << "大于10的元素个数:" << res << endl;
    
    	//查找小于10的元素的个数 
    	res = count_if(v.begin(), v.end(), bind1st(greater(), 10));// x op value,即 10 greater elem,10 > elem,小于10的元素
    	cout << "小于10的元素个数:" << res << endl;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    bind2nd(greater(), 10));// value op x,即 elem greator 10,elem > 10,大于10的元素
    bind1st(greater(), 10));// x op value,即 10 greater elem,10 > elem,小于10的元素
    在这里插入图片描述

    4.2 for_each()遍历容器

    之前用迭代器遍历容器

    void printVector(vector& v) {
    	vector::iterator it = v.begin();
    	for (; it != v.end(); it++)
    		cout << *it << " ";
    	cout << endl;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    for_each()遍历容器

    //定义方法
    class printVectorInt {
    public:
    	void operator()(int val) {
    		cout << val << " ";
    	}
    };
    
    //for_each()遍历容器
    void test5() {
    	vector v;
    	v.push_back(10);
    	v.push_back(50);
    	v.push_back(60);
    	v.push_back(30);
    	v.push_back(10);
    
    	//注意for_each()里面是逗号,不是分号
    	for_each(v.begin(), v.end(), printVectorInt());
    	cout << endl;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    在这里插入图片描述

    4.3 输出各元素统一加一个值;

    比如+100 ;;cout << val + 100<< " ";

    class printVectorInt {
    public:
    	void operator()(int val) {
    		cout << val + 100<< " ";
    	}
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    在这里插入图片描述

    但是这样是在仿函数里面修改,
    我们希望函数写好后就不再修改,在调用的时候,修改调用入口参数;

    //第二步:公共继承 binary_function 参数萃取
    class printVectorInt:binary_function {
    public:
    	//第三步:const修饰operator()
    	void operator()(int val, int temp) const{
    		//cout << val + temp << " ";
    		cout << "val = " <
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    bind1st是绑定第一个参数,bind2nd则是绑定第二个参数。
    在这里插入图片描述
    在这里插入图片描述
    不知道为啥,我在VS2022上无法运行,
    提示我的printVectorInt使用私有去继承公共继承 binary_function,,,,不懂
    在这里插入图片描述

    4.4 函数指针适配器 ptr_fun

    //普通函数名 作为适配器
    void printVectorInt(int val, int temp){
    	cout << "val = " << val << "  temp = " << temp << endl;
    }
    
    //for_each()遍历容器
    void test4() {
    	vector v;
    	v.push_back(10);
    	v.push_back(50);
    	v.push_back(60);
    	v.push_back(30);
    	v.push_back(10);
    
    	//注意for_each()里面是逗号,不是分号
    	//第一步: bind2nd或bind1st绑定参数
    	for_each(v.begin(), v.end(), bind1st(ptr_fun(printVectorInt), 200));
    	cout << endl;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    在这里插入图片描述

    for_each(v.begin(), v.end(), bind2nd(ptr_fun(printVectorInt), 200));
    在这里插入图片描述

    4.5 成员函数 作为适配器 mem_fun_ref

    //成员函数 作为适配器 mem_fun_ref
    class Data {
    public:
    	Data() {}
    	Data(int val) {
    		this->data = val;
    	}
    	void printVectorInt(int temp) {
    		cout << "val = " << data << "  temp = " << temp << endl;
    	}
    
    	int data;
    };
    
    
    void test5() {
    	vector v;
    	v.push_back(Data(10));
    	v.push_back(Data(50));
    	v.push_back(Data(60));
    	v.push_back(Data(30));
    	v.push_back(Data(10));
    
    	//注意for_each()里面是逗号,不是分号
    	//第一步: bind2nd或bind1st绑定参数
    	for_each(v.begin(), v.end(), bind2nd(mem_fun_ref(&Data::printVectorInt), 200));
    	cout << endl;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    在这里插入图片描述

    4.6 取反适配器

    4.6.1 not1 一元取反

    //取反适配器
    void test6() {
    	vector v;
    	v.push_back(10);
    	v.push_back(50);
    	v.push_back(60);
    	v.push_back(30);
    	v.push_back(10);
    	vector::iterator ret;
    	//bind2nd(greater(), 30),,查找 >30的第一个元素,,前面加not1后,变成查找 <=30的第一个元素
    	ret = find_if(v.begin(), v.end(), not1(bind2nd(greater(), 30)));
    	if(ret != v.end())
    		cout <<"找到相关数据:"<<*ret<< endl;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    在这里插入图片描述

    4.6.2 not2 二元取反

    //not2 二元取反
    void test7() {
    	vector v;
    	v.push_back(10);
    	v.push_back(50);
    	v.push_back(60);
    	v.push_back(30);
    	v.push_back(10);
    	
    	//lambda 表达式 c++11才支持
    	//[]里面啥都不写 lambda不能识别 外部数据
    	//[=] lambda能对 外部数据 读操作
    	//[&] lambda能对 外部数据 读写操作
    
    	for_each(v.begin(), v.end(), [&](int val) {cout << val << " "; });
    	cout << endl;
    
    	//greater() 内建函数对象 降序策略,,not2取反后,变为升序排列
    	sort(v.begin(),v.end(),not2(greater()));
    
    	for_each(v.begin(), v.end(), [&](int val) {cout << val <<" "; });
    	cout << endl;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    在这里插入图片描述

    运行到sort的二园区反,就终止。为何?不知道
    在这里插入图片描述

  • 相关阅读:
    MySQL数据库集群技术主从自动协商详细讲解
    C++基础知识(九)--- 类型转换 & 异常
    不是所有数据增强都可以提升精度
    VulnHub narak
    什么是CAP理论?
    spark sql之巧用group by
    k8s--基础--22.10--storageclass--类型--Azure 磁盘
    shell
    Java VMTranslator Part II
    MyBatis foreach标签有什么作用呢?
  • 原文地址:https://blog.csdn.net/m0_51233386/article/details/126556079