标准库bind函数
bind函数可以看作一个通用的函数适配器,它接受一个可调用对象,生成一个新的可调用对象来"适应"原对象的参数列表。
调用bind的一般形式为:
auto newCallable = bind(callable,arg_list);
其中,newCallabe本身是一个可调用对象,arg_list是一个逗号分隔的参数列表,对应给定的newCallable的参数。即,当我们调用newCallable时,newCallable会调用callable,并传给它arg_list中的参数。
arg_list中的参数可能包含形如_n的名字,其中n手机一个整数。这些参数是"占位符",表示newCallable的参数,它们占据了传递给newCallable的参数的"位置"。数值n表示生成的可调用对象中参数的位置:_1为newCallable中的第一个参数,_2为第二个参数,以此类推。
举个例子。
//check是一个可调用对象,接受一个string类型的参数
//并用此string和值6来调用
check_tmp auto check = bind(check_tmp,_1,6);
此bind只有一个占位符,表示check只接受单一参数。占位符出现在arg_list的第一个位置,表示check的此参数对应check_tmp的第一个参数,此参数是一个const string。因此,调用check必须传给它一个string类型的参数,check会将此参数传递给check_tmp。
string s = "hello world"; bool t = check(s);
//check(s)会调用check_tmp(s,6)
使用placeholders名字
名字_n都定义在一个名为placeholders的命名空间中,而这个命名空间本身定义在std命名空间中。为了使用这些名字,两个命名空间都要写上。
举个例子。
using std::placeholders::_1;
这样很麻烦。
简化一下。
using namespace std::placeholders;
bind的参数
直接举例子。
//g是一个由两个参数的可调用对象
auto g = bind(f,a,b,_2,c,_1);
//当我们调用
g(X,Y);
//映射为
f(a,b,Y,c,_X);
//是会改变参数顺序的
绑定引用参数
默认情况下,bind的那些不是占位符的参数被拷贝到bind返回的可调用对象中。不过有些绑定的参数我们希望以引用方式传递,或是要绑定的参数的类型无法拷贝。
举个例子。
ostream &print(ostream &os,const string &s,char c){ return os <<s <<c; }
但是,不能直接用bind来代替对os的捕获:
//错误,不能拷贝os
bind(print,os,_1,' ');
原因在于bind拷贝其参数,而我们不能拷贝一个ostream。如果我们希望传递给bind一个对象又不拷贝它,就必须使用标准库ref函数:
bind(print,ref(os),_1," ");
函数ref返回一个对象,包含给定的引用,此对象是可以拷贝的。