参考文档:
【C++11】std::bind及std::placeholders_我要精通C++的博客-CSDN博客_std::bind std::placeholders
1:摘自《Effective Modern C++》中一段对std::bind描述的话
std::bind is the C++11 successor to C++98’s std::bind1st and std::bind2nd,
but, informally, it’s been part of the Standard Library since 2005. That’s when the
Standardization Committee adopted a document known as TR1, which included
bind’s specification. (In TR1, bind was in a different namespace, so it was
std::tr1::bind, not std::bind, and a few interface details were different.) This
history means that some programmers have a decade or more of experience using
std::bind. If you’re one of them, you may be reluctant to abandon a tool that’s
served you well. That’s understandable, but in this case, change is good, because in
C++11, lambdas are almost always a better choice than std::bind. As of C++14, the
case for lambdas isn’t just stronger, it’s downright ironclad.
std::bind是C++11对C++98中对std::bind1st和std::bind2nd的继承,但是,非正式地说,
它自2005年以来一直是标准库的一部分.标准化委员会通过了一份称为TR1的文件,其中包
括bind的具体实现(在TR1中,bind位于不同
的命名空间中,因此它是std::tr1::bind而不是std::bind,有几个接口细节是不一样的)
这段历史意味着一些程序员有十年或更长时间的使用绑定.如果你是其中之一,你可能不
愿意放弃一个工具,这是可以理解的,但在这种情况下,变化是好的,因为在在C++11中,lambdas
几乎总是比std::bind更好的选择.lambdas(兰布达斯)的理由不仅仅是更有力,而是无懈可击。
学习纲要:
- std::bind() 思想,头文件以及原型
- std::placeholders()思想,头文件及原型
- std::bind() 单独使用(绑定普通函数,绑定类的成员函数,绑定一个引用参数)
- std::bind()和std::placeholders混用(减少参数个数,调整参数次序
std::bind() 思想,头文件以及原型
简介:
- std::bind是这样一种机制,它可以预先把指定可调用实体的某些参数绑定到已有变量,产生一个新的可调用实体。
- 可将std::bind函数看做一个通用的函数适配器,它接收一个可调用对象生成一个新的可调用对象来 “适配”原函数参数列表
- std::bind将原可调用对象与其参数一起绑定后,新的可调用对象可以使用:std::function保存。
作用:
将可调用对象和其参数变得成一个仿函数
- 你绑定原可调用对象参数
- 只绑定原可调用对象部分参数,从而可以减少对象传入的参数
- 绑定原可调用对象参数次序变换
使用场景:
先将可调用的对象保存起来,在需要的时候再调用,是一种延迟计算的思想,不论是普通函数,函数对象,还是成员函数,成员变量都可以绑定。
头文件
#include<functional>
原型:
template< class F, class... Args > /*unspecified*/ bind( F&& f, Args&&... args ); template< class R, class F, class... Args > /*unspecified*/ bind( F&& f, Args&&... args );
f - Callable object (function object, pointer to function, reference to function, pointer to member function, or pointer to data member) that will be bound to some arguments args - list of arguments to bind, with the unbound arguments replaced by the placeholders
_1,
_2, _3...
of namespacestd::placeholders
std::bind()::placeholders 思想及作用
#include <iostream> #include <functional> using namespace std; int TestFunc(int a, char c, float f) { cout << a << endl; cout << c << endl; cout << f << endl; return a; } int main() { auto bindFunc1 = bind(TestFunc, std::placeholders::_1, 'A', 100.1); bindFunc1(10); //等于TestFunc(10,'A', 100.1) cout << "=================================\n"; auto bindFunc2 = bind(TestFunc, std::placeholders::_2, std::placeholders::_1, 100.1); bindFunc2('B', 10); //等于TestFunc(10,'B', 100.1) cout << "=================================\n"; auto bindFunc3 = bind(TestFunc, std::placeholders::_2, std::placeholders::_3, std::placeholders::_1); bindFunc3(100.1, 30, 'C'); //等于TestFunc(30,'C', 100.1) return 0; }
- 上面这段代码主要说的是bind中std::placeholders的使用。 std::placeholders是一个占位符。当使用bind生成一个新的可调用对象时,
- std::placeholders表示新的可调用对象的第 几个参数和原函数的第几个参数进行匹配。
1: std::bind单独使用,绑定普通函数
double myDivide(double x,double y){
// 取商
return x/y;
}
int main(){
// bind的第一个参数是函数名,普通函数做实参时,会隐式转换成函数指针
// 所以:sid::bind(myDivide,1,2)等价于std::bind(&myDivide,1,2)
auto fn_half = bind(myDivide,1,3);
cout<< fn_half()<< endl;
}
// 打印
0.333333
1.1:std::bind单独使用,绑定类的成员函数
struct Foo {
void print_sum(int n1,int n2){
std::cout << n1+ n2<< '\n';
}
int data = 10;
};
int main(){
/**
bind 绑定类成员函数时,第一个参数表示对象的成员函数的指针,第二个参数表示对象的地址
必须显示的指定 &Foo::print_sum ,
因为编译器不会将对象的成员函数隐式转换成函数指针
所以必须在 Foo::print_sum 前添加 &
使用对象成员函数的指针时,必须要知道该指针属于哪个对象,因此第二个参数为对象的地址 &foo
*/
Foo foo;
auto f = std::bind(&Foo::print_sum,&foo,95,5);
f(); // 100
}
1.2: std::bind单独使用,绑定一个引用参数
ostream& print(ostream& os,const string& s, char c){
os<< s << c;
return os;
}
int main(){
ostringstream os1;
// ostream不能拷贝,如果希望传递给bind一个对象,但是不拷贝它。
// 就必须使用标准库提供的 ref函数。
for_each(words.begin(),words.end(),
bind(print,ref(os1),std::placeholders::_1,c));
cout << os1.str() << endl;
}
打印
hello world this is C++11
1.3: 使用std::bind和 std::placeholders混用达到减少参数使用和调整参数次序的效果
double myDivide(double x,double y){
// 取商
return x/y;
}
int main(){
// std::bind和std::placeholders混用达到减少参数使用和调整参数次序的效果
// 减少一个参数
auto fn_half_1 = std::bind(myDivide,std::placeholders::_1,2);
std::cout<< fn_half_1(1) << std::endl; // myDivie(1,2) 0.5
// 减少两个参数
auto fn_half_2 = std::bind(myDivide,1,2);
std::cout<< fn_half_2()<< std::endl; // myDivie(1,2) 0.5
// 将调用的第一个参数和第二个参数互换
auto fn_half_3 = std::bind(myDivide,std::placeholders::_2,std::placeholders::_1);
std::cout<< fn_half_3(1,2)<<endl; // myDivide(2,1) // 2
}
1.4: 使用std::bind和std::placeholders达到调整参数次序的效果的另一个例子
int TestFunc(int a,char c, float f){
std::cout << a<< std::endl;
std::cout << c<< std::endl;
std::cout << f<< std::endl;
return a;
}
// 第一个参数和函数第一个参数匹配(int),第二个参数和第二个参数匹配(char),第三个参数和第三个参数匹配
auto fun1 = bind(TestFunc,placeholders::_1,placeholders::_2,placeholders::_3);
// 通过占位符调整顺序,第二个参数和原函数第一个参数匹配,第三个参数和原函数第二个参数匹配,第一个参数和原函数第三个函数匹配
auto fun2 = bind(TestFunc,placeholders::_2,placeholders::_3,placeholders::_1);
// 第一个参数和原函数第一个参数匹配,第二个参数和原函数第二个参数匹配,第三个参数默认98.77
auto fun3 = bind(TestFunc,placeholders::_1,placeholders::_2,98.77);
int main(){
fun1(30,'C',100.1);
cout<< "-------"<< endl;
fun2(100.1,30,'C');
cout<< "-------"<< endl;
fun3(30,'C');
cout<< "-------"<< endl;
fun3(30,'C',9.8); // 9.8 会被忽略
}
// 打印
30
C
100.1
-------
30
C
100.1
-------
30
C
98.77
-------
30
C
98.77