std::bind用法
文章目录1. 介绍1.1 函数原型2. 占位符3. 绑定函数3.1 绑定普通函数3.2 绑定类成员函数3.3 绑定一个引用参数3.4 绑定类静态函数4. 和std::function的关系1. 介绍C11中的bind()函数是用来提供可调用函数对象和参数绑定关系的。绑定后的结果可以使用std::function保存。std::bind主要有以下两个作用将可调用对象和其参数绑定成一个仿函数只绑定部分参数减少可调用对象传入的参数。其可以支持普通函数、函数对象和成员函数的绑定而且支持占位。所谓占位其实就是比如下面这样autopFunstd::bind(func,std::placeholders::_1,std::placeholders::_2);当需要对函数func进行调用时可以通过绑定关系进行调用pFun(4,5);1.1 函数原型bind()函数提供了两种函数原型// 函数原型1templateclassF,class...Args/*使用方法*/bind(Ff,Args...args);// 函数原型2templateclassR,classF,class...Args/*使用方法*/bind(Ff,Args...args);两种函数原型的区别就在于提供了一个可调用函数对象的入参用于普通函数绑定提供了两个可调用函数对象的入参用于成员函数绑定具体使用方法见章节3示例2. 占位符下面看一下bind函数中的占位符的使用但同时我们在对函数进行绑定时也可以不传入占位符。下面代码块的将在代码结束后解释functional库文件是必须的.#includefunctional#includeiostreamusingnamespacestd;inttestFun(inta,floatb,charc){couta b cendl;}intmain(){//1autobindFun1bind(testFun,std::placeholders::_1,100.1,A);bindFun1(10);//10 100.1 A//2autobindFun1bind(testFun,std::placeholders::_1,std::placeholders::_2,A);bindFun1(10,88.88);//10 88.88 A//3autobindFun1bind(testFun,std::placeholders::_1,std::placeholders::_2,std::placeholders::_3);bindFun1(10,88.88,D);//10 88.88 D//4autobindFun1bind(testFun,std::placeholders::_3,std::placeholders::_1,std::placeholders::_2);bindFun1(88.88,D,10);//10 88.88 D}对于前面三种调用方式得到如上输出比较好理解占位符和入参都是一一对应的第四种调用方式改变了入参的顺序和占位符的顺序。bind函数在进行绑定时占位符去找入参第一个占位符是::_3函数调用中的入参第三个是10第二个占位符是::_1函数调用中的入参第二个是88.88第二个占位符是::_2函数调用中的入参第一个是’D’所以真正的函数调用就是testFun(10 D88.88)3. 绑定函数3.1 绑定普通函数见章节2中占位符的使用方法.3.2 绑定类成员函数绑定类成员函数时第一个入参为函数对象的函数指针第二个参数表示对象的地址类对象必须已经定义必须显示的指定Base::display因为编译器不会将对象的成员函数隐式的转换为函数指针.#includeiostream#includefunctionalusingnamespacestd;classBase{public:voiddisplay(inta,intb){coutabendl;}};intmain(){Base base;autopFun1bind(Base::display,base,std::placeholders::_1,100);pFun(100);//it should be output 200.autopFun2bind(Base::display,base);pFun(100,200);//it should be output 300.}3.3 绑定一个引用参数bind函数中那些不是使用占位符传入的参数是使用参数拷贝的方式传递给函数的当入参为一个比较大的结构体或者类对象时使用拷贝传参会比较耗费性能bind函数同样具有引用的方式传参具体方法如下#includeiostream#includefunctionalusingnamespacestd;usingnamespacestd::placeholders;ostreamosprintInfo(ostreamos,conststringstr,charc){osstrcendl;returnos;}intmain(){ostringstream os;autopFun1bind(printInfo,std::ref(os),_1,_2);autopFun2bind(printInfo,_1,_2,_3);pFun2(std::ref(os),s,c);}上面的代码中函数printInfo需要一个引用型的流对象和两个用于输出的参数:当需要绑定一个引用型的参数时可以使用std::ref关键字对其进行标识这样就不会再将整个对象拷贝入参。占位符可以进行简化前提是把命名空间直接加进来3.4 绑定类静态函数不需要传类地址std::functionvoid()funcstd::bind(MyClass::func);4. 和std::function的关系std::bind返回的是一个实现相关的可调用对象仿函数其类型由模板推导产生非常复杂且不便于直接声明因此在实际开发中通常配合std::function一起使用。二者的关系可以简单理解为std::bind负责“制造”一个可调用对象而std::function负责“存储并统一调用”这个对象。std::function是 C11 引入的通用可调用对象包装器它可以统一保存普通函数指针成员函数指针std::bind返回的绑定表达式Lambda表达式#includeiostream#includefunctionalintadd(inta,intb){returnab;}intmain(){// 方式一直接用 auto 推导 bind 的返回类型autof1std::bind(add,std::placeholders::_1,10);std::coutf1(5)std::endl;// 15// 方式二更常见用 std::function 保存 bind 的结果std::functionint(int)f2std::bind(add,std::placeholders::_1,20);std::coutf2(5)std::endl;// 25// std::function 同样可以保存普通函数和 Lambdastd::functionint(int,int)f3add;std::functionint(int,int)f4[](inta,intb){returna-b;};std::coutf3(8,2)std::endl;// 10std::coutf4(8,2)std::endl;// 6return0;}使用std::function保存std::bind结果主要有以下好处类型明确bind的返回类型晦涩难懂std::function以“函数签名”的方式让代码一目了然。统一接口无论底层是普通函数、成员函数还是 Lambda都可以用同一种std::function类型存储和调用。便于传递例如在回调注册、异步任务、事件处理等场景中可以用std::function作为参数类型接收各种可调用对象。支持运行时替换std::function内部实现类似类型擦除同一个std::function对象可以在运行时被重新赋值为不同的可调用对象。需要注意std::function会带来一定的间接调用开销对性能极其敏感的场景仍推荐使用模板或auto直接推导bind的返回类型。