C++ STL新特性:not1 not2 mem_fun mem_fun_ref mem_fn等函数(详解+示例代码)
建议先补充基础知识,否则生啃本节可能会有一定难度:
C++STL:仿函数
C++STL: bind函数绑定
谓词
首先来解释一下,什么是谓词? 当我们调用一个仿函数的时候,我们的仿函数重载的括号运算符函数接受的参数数量决定了是一元谓词,还是二元谓词:
- 一元谓词:仿函数接受一个参数,比如输入一个数字和一个固定的10比较,判断这个数是否有大于10 。这个仿函数就是接受一元谓词的仿函数。
class Greater1 { public: bool operator()(const int& a)const { return a > 10; } };
- 二元谓词:仿函数接受两个参数,他们两个进行操作,这个仿函数就是接受二元谓词的仿函数。
class Greater2 { public: bool operator()(const int& a,const int& b)const { return a > b; } };
not1函数
作用:对接受一元谓词的仿函数取反
。
指定类型
//not:对一元谓词的仿函数取反 class Greater1 { public: using argument_type = int; bool operator()(const int& val)const { return val > 10; //大于10吗 } }; cout << boolalpha << Greater1()(50) << endl; //正常的仿函数 auto _less1 = not1(Greater1()); //给我们自己制作的一元谓词仿函数取反 cout << boolalpha << "not1我做的: " << _less1(50) << endl;
需要注意的点:
- 为什么要在仿函数中加argument_type这个东西?
解:我们按F12进入not1的定义可以发现:所谓的not1其实也是一个仿函数,叫做unary_function,我们把函数的指针传递给他,所以它就具有了一个函数,它接受一个argument_type的东西做为它的重载括号运算符的形参类型,它有默认的result_type作为它的返回值bool,然后直接对这个函数取反,这样就会形成了我们的一元谓词仿函数的取反。(原理就是这么简单明了)
- not1 只能对接受一元谓词的仿函数取反,无法对二元谓词取反,我们可以用not2。
***继承标准库
我们也可以不在我们的仿函数指定argument_type,直接继承。
//not:对一元谓词的仿函数取反 class Greater1:public unary_function<int,bool> { public: bool operator()(const int& val)const { return val > 10; //大于10吗 } }; cout << boolalpha << Greater1()(50) << endl; auto _less1 = not1(Greater1()); //给我们自己制作的一元谓词仿函数取反 cout << boolalpha << "not1我做的: " << _less1(50) << endl;
需要注意的点:
- 我们通过上一个讲解,可以知道not1的原型为unary_function,接受两个参数,直接继承此类,然后传递两个参数类型,一个是一元谓词类型,一个是返回类型,即可实现和上一个一样的功能。
not2函数
指定类型
class Greater2 { public: using first_argument_type = int; using second_argument_type = int; bool operator()(const int& a,const int& b)const { return a > b; } }; cout << boolalpha << Greater2()(5, 10) << endl; auto _My_less = not2(Greater2()); //给我们自己制作的二元谓词仿函数取反 cout << boolalpha << "not2我做的: " << _My_less(5, 10) << endl;
需要注意的点:
- 和我们的一元谓词一样,我们的not2二元谓词的原型是:first… 和second…分别作为第一个参数类型和第二个参数类型,默认返回为bool,所以我们直接指定first和second的类型,即可做到对二元谓词仿函数取反。
***继承标准库
//not2:对二元谓词的仿函数取反 class Greater2:public binary_function<int,int,bool> { public: bool operator()(const int& a,const int& b)const { return a > b; } }; cout << boolalpha << Greater2()(5, 10) << endl; auto _My_less = not2(Greater2()); //给我们自己制作的二元谓词仿函数取反 cout << boolalpha << "not2我做的: " << _My_less(5, 10) << endl;
和上面一样,我们直接继承标准库not2的原型 binary_function,分别指定他们的类型,即可。
mem_fun函数
作用:把类成员函数转换为函数对象(仿函数),使用对象指针进行绑定
。
示例说明:
class Ani { public: int number = 0; void printDog() { cout << __FUNCTION__ << " 汪汪汪: " << number++ << endl; } void printCat() { cout << __FUNCTION__ << " 喵喵喵: " << number++ << endl; } }; int main() { Ani d; auto func1 = mem_fun(&Ani::printDog); //传递成员函数指针, func1(&d); //把成员函数转换为函数对象,使用可调用对象调用成员函数 d.printDog(); }
mem_fun函数:把成员函数转换为函数对象,使用对象指针进行绑定,在调用的时候使用对象的指针(不能传递临时对象),即取地址的形式传入到func1函数中,以此来调用绑定的函数。
为什么要传递地址?
解析: mem_fun函数标准库原型:就是一个函数对象(仿函数),在重载的括号运算符里,使用了指针进行访问,因此在使用在个函数时,需要传递对象的指针。
mem_fun_ref函数
作用:把类成员函数转换为函数对象(仿函数),使用对象引用进行绑定
。
class Ani { public: int number = 0; void printDog() { cout << __FUNCTION__ << " 汪汪汪: " << number++ << endl; } void printCat() { cout << __FUNCTION__ << " 喵喵喵: " << number++ << endl; } }; int main() { Ani c; auto fun2 = mem_fun_ref(&Ani::printCat); //传递成员函数指针 fun2(c); c.printCat(); return 0; }
mem_fun_ref:与mem_fun类似,只不过它是按照对象的引用进行绑定的,即在调用此函数时,不用取地址符号,它传递的是对象的引用。
注意:不能传递临时对象。
进入到mem_fun_ref的标准库原型:可以看到它也是一个仿函数,重载的括号运算符是按照引用传递的,其他的基本和mem_fun类似。
mem_fn函数
作用:把类成员函数转换为函数对象(仿函数),使用对象引用,指针,临时对象都能进行绑定
。
class Ani { public: void Anis(int a,int b,int c) { cout << a << " " << b << " " << c << endl; } }; int main() { Ani all; auto fun3 = mem_fn(&Ani::Anis); fun3(Ani(), 1, 2, 3); fun3(&all, 1, 2, 3); fun3(all, 1, 2, 3); return 0; }
与前两个分别按指针和引用进行绑定的类似,但不能按临时对象绑定相比。mem_fn可以绑定指针,引用,临时对象等三种都可以。
函数绑定示例
请认真看这个示例:
class Num { public: Num(const int& data) :val(data) {} void travel() { cout << val << " "; } private: int val; }; int main() { vector<Num> a; for (int i = 0; i < 10; ++i) { a.emplace_back(i); } //将成员函数转变为函数对象 for_each(a.begin(), a.end(),mem_fn(&Num::travel)); cout << endl; for_each(a.begin(), a.end(), mem_fun_ref(&Num::travel)); cout << endl; cout << endl; vector<Num*> b; for (int i = 0; i < 10; ++i) { b.emplace_back(new Num(i * 2)); } for_each(b.begin(), b.end(), mem_fun(&Num::travel)); return 0; }
解析:
- 第一个vector: 每一个元素都是一个Num,所以我们可以利用mem_fn或者mem_fun_ref函数将
类成员函数转换为 函数对象(仿函数)
,然后for_each算法接受此函数对象,传递进去,最后可以打印出vector的值 - 第二个vector:每一个元素都是一个Num的指针,所以我们只能使用mem_fun函数
将类成员函数转换为 函数对象
,使用指针进行绑定,因此mem_fun只接受指针类型的对象,所以无法使用前两个函数。
他们都提供了打印容器的合适函数类型,为函数的转换提供了方法:
本文来自博客园,作者:hugeYlh,转载请注明原文链接:https://www.cnblogs.com/helloylh/p/17209706.html
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· 写一个简单的SQL生成工具
· AI 智能体引爆开源社区「GitHub 热点速览」
· C#/.NET/.NET Core技术前沿周刊 | 第 29 期(2025年3.1-3.9)