【C++11 新特性】bind(二)
一、C++11为什么要引入std::bind?
C++11 引入了std::bind
,顾名思义,是用来绑定函数调用的某些参数的。std::bind
能改造现有函数,生成新的函数。举例说明,现在有这么个函数声明:
int f(int a, int b);
我现在需求,我要一个有 2 个 int 类型参数的函数,并且第二个参数默认为 2。你可千万不要屁颠屁颠的在去写一个f(int i, int i = 2)
,这里std::bind
的作用体现出来了,看:
std::bind(&f, std::placeholders::_1, 2);
好了,std::bind
之后的返回值,那就可以拜托给我们的std::funtion
同学了,我们定义个函数类型:
std::function<int(int,int)> fun = std::bind(&f, std::placeholders::_1, 2);
把std::bind
的返回值给 fun,于是我们就生成了一个 b 强制为 2,只有 1 个int a
参数的 fun 新函数。
最后要说一句,std::bind
返回后的函数和原函数是 2 个完全不同的函数,这个你可以通过打印他们的内存地址看出来,这个就交给各位看官自己去实现了。
二、概述
std::bind
函数定义在头文件<functional>
中,是一个函数模板,它就像一个函数适配器,接受一个可调用对象(callable object),生成一个新的可调用对象来“适应”原对象的参数列表。
使用std::bind
可以将可调用对象和参数一起绑定,绑定后的结果使用std::function
进行保存,并延迟调用到任何我们需要的时候,所以经常用来实现回调函数。
std::bind
通常有两大作用:
- 将可调用对象与参数一起绑定为另一个
std::function
供调用 - 将 n 元可调用对象转成 m(m < n) 元可调用对象,绑定一部分参数,这里需要使用
std::placeholders
三、函数原型
std::bind
函数有两种函数原型,定义如下:
template <class Fn, class... Args>
/* unspecified */ bind (Fn&& fn, Args&&... args);
template <class Ret, class Fn, class... Args>
/* unspecified */ bind (Fn&& fn, Args&&... args);
1. 函数模板说明
- 基于参数
fn
返回一个函数对象,并且以args
参数绑定为函数对象的参数。 - 每个参数要么绑定一个参数值,要么绑定为一个
std::placeholders
(占位符,如 _1, _2, ..., _n)。 - 如果参数绑定成一个值,那么返回的函数对象将总使用绑定的参数值做为调用参数,即调用传入参数将不起作用;如果参数绑定为
std::placeholders
,那么返回的函数对象在被调用时需要传入实时参数,参数填充的位置即由placeholder
指定的序号。
2. 函数模板参数说明
fn
:可调用的函数对象,比如函数对象、函数指针、函数引用、成员函数或者数据成员函数。args
:需要绑定的函数的参数列表,使用命名空间占位符std::placeholders::_1
,std::placeholders::_2
标志参数,其中std::placeholders::_1
标志为参数列表中的第一个参数,std::placeholders::_2
标志参数列表中的第二个参数,std::placeholders::_3
标志参数列表中的第三个参数,以此类推。
3. 函数模板返回值说明
返回一个函数对象,该函数在调用时使用参数列表args
来调用fn
。如果fn
是指向类的成员函数,则返回函数第一个参数应该是该类的成员、或者成员对象的引用、或者是成员对象的指针。
四、示例
#include <iostream>
#include <functional>
// 普通函数
int testFun(int a, int b) {
return a + b;
}
// Lambda表达式
auto lamdaExps = [](int a, int b) {
return a + b;
};
// 仿函数
class Functor {
public:
int operator()(int a, int b) {
return a + b;
}
};
// 1.类成员函数
// 2.类静态成员函数
class TestClass
{
public:
int classMemberFun(int a, int b) { return a + b; }
static int staticMemberFun(int a, int b) { return a + b; }
};
int main() {
// 绑定普通函数(使用占位符先占位,然后执行时再传参)
auto bindFun = std::bind(&testFun, std::placeholders::_1, std::placeholders::_2);
int ret = bindFun(10, 5);
std::cout << "普通函数_1:" << ret << std::endl;
// 绑定普通函数(也可以只使用一个占位符来占位,指定一个参数)
auto bindFun2 = std::bind(&testFun, std::placeholders::_1, 8);
ret = bindFun2(10);
std::cout << "普通函数_2:" << ret << std::endl;
// 绑定Lambda表达式
auto bindFun3 = std::bind(lamdaExps, std::placeholders::_1, std::placeholders::_2);
ret = bindFun3(10, 20);
std::cout << "Lambda表达式:" << ret << std::endl;
// 绑定仿函数
Functor testFunctor;
auto bindFun4 = std::bind(testFunctor, std::placeholders::_1, std::placeholders::_2);
ret = bindFun3(10, 30);
std::cout << "仿函数:" << ret << std::endl;
// 绑定类成员函数
TestClass testObj;
auto bindFun5 = std::bind(&TestClass::classMemberFun, testObj, std::placeholders::_1, std::placeholders::_2);
ret = bindFun5(10, 40);
std::cout << "类成员函数:" << ret << std::endl;
// 绑定类静态成员函数
auto bindFun6 = std::bind(&TestClass::staticMemberFun, std::placeholders::_1, std::placeholders::_2);
ret = bindFun6(10, 50);
std::cout << "类静态成员函数:" << ret << std::endl;
return 0;
}
结果如下:
普通函数_1:15
普通函数_2:18
Lambda表达式:30
仿函数:40
类成员函数:50
类静态成员函数:60
关于绑定模块函数、模板类的示例可以参考:C++11 - std::bind简要介绍以及可绑定函数的几种形式总结
参考:
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 没有源码,如何修改代码逻辑?
· 一个奇形怪状的面试题:Bean中的CHM要不要加volatile?
· [.NET]调用本地 Deepseek 模型
· 一个费力不讨好的项目,让我损失了近一半的绩效!
· .NET Core 托管堆内存泄露/CPU异常的常见思路
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· NetPad:一个.NET开源、跨平台的C#编辑器
· PowerShell开发游戏 · 打蜜蜂
· 凌晨三点救火实录:Java内存泄漏的七个神坑,你至少踩过三个!