标准库bind函数
可以将bind函数看作一个通用的函数适配器,它接受一个可调用对象,生成一个新的可调用对象来“适应”原对象的参数列表。
调用bind的一般形式为:
auto newCallable = bind(callable, arg_list);
其中newCallable本身是一个可调用对象,arg_list是一个逗号分隔的参数列表,对应给定的callable的参数。即,当我们调用newCallable时,newCallable会调用callable,并传递给他arg_list中的参数。
arg_list中的参数可能包含形如_n的名字,其中n使一个整数。这些参数是“占位符”,表示newCallable的参数,它们占据了传递给newCallable的参数的位置。数值n表示生成的可调用对象中参数的位置:_1为newCallable的第一个参数,_2为第二个参数,以此类推。
绑定check_size的sz参数
作为一个简单的例子
bool check_size(const string& s, string::size_type sz)
{
return s.size() >= sz;
}
我们使用bind生成一个调用check_size的对象,如下所示,它用一个定值作为其大小参数来调用check_size:
//check6是回一个可调用对象,接受一个string类型的参数
//并用此string和值6来调用check_size
auto check6 = bind(check_size, _1, 6)
此bind调用只有一个占位符 ,表示check6只接受单一参数。占位符出现在arg_list的第一个位置,表示check6的此参数对应check_size的第一个参数。此参数是一个const string&。因此,调用check6必须传递给它一个string类型的参数,check6会将此参数传递check_size.
string s = "hello";
bool b1 = check6(s); //check6(s)会调用check_size(s, 6)
使用bind
int sz = 5;
auto wc = find_if(words.begin(), words.end(), bind(check_size, _1, sz));
此bind调用生成一个可调用对象,将check_size的第二个参数绑定到sz的值。当find_if对words中的string调用这个对象时,这些对象会调用check_size,将给定的string和sz传递给它。
使用placeholders名字
名字_n都定义在一个名为placeholders的命名空间中,而这个命名空间本身定义在std命名空间。在使用时可以声明
using namespace std::placeholders;
与bind函数一样,placeholders命名空间也定义在functional头文件中。
bind的参数
我们可以用bind绑定给定可调用对象中的参数或重新安排其顺序。例如
auto g = bind(f, a, b, _2, c, _1);
生成一个新的可调用对象,它有两个参数,分别别占用符_2和_1表示。这个新的可调用对象将它自己的参数作为第三个和第五个参数传递给f,f的第一个、第二个和第四个参数分别被绑定到给定的值a,b,c上。
传递给g的参数绑定到占位符,即,第一个参数绑定到_1,第二个绑定到_2.当我们调用g时,其第一个参数将被传递给f作为最后一个参数,第二个参数将被传递给f作为第三个参数,实际上,这个bind调用会将
g(_1, _2)
映射为
f(a, b, _2, c, _1);
即,对g的调用会调用f,用g的参数代替占位符,再加上绑定的参数a,b,c。例如调用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
for_each(words.begin(), words.end(), bind(print, os, _1, ''));
原因在于bind拷贝其参数,而我们不能拷贝一个ostream.如果我们希望传递给bind一个对象而又不拷贝它,就必须使用标准库的ref函数:
for_each(words.begin(), words.end(), bind(print, ref(os), _1, ' '));
函数ref返回一个对象,包含给定的引用,此对象是可以拷贝的。标准库还有一个cref函数,生成一个保存const引用的类,与bind一样,ref和cref也定义在头文件functional中。