前言
为什么要引入bind函数?
对于那种只在一两个地方使用的简单操作,使用lambda是最有用的。
如果我们需要在很多地方使用相同的操作,通常应该定义一个函数,而不是编写多个相同的lambda表达式。
如果lamnda函数的捕获列表为空,通常我们可以使用函数代替。
但是对于捕获局部变量的lambda,就需要bind
函数来帮忙。
所以bind函数的应用场景,通常和传入谓词有关的STL泛型算法相关联。
参数绑定
通俗的说,bind函数就是将原本的函数做了一层包装,然后露出来新的参数列表来与外界交互。
- 头文件functional
- 可以当做一个通用的函数适配器(类比容器适配器的概念)
- 接收可调用对象,生成新的可调用对象来配合源对象的参数列表
bind的一般形式:
auto newCallable = bind(callable, arg_list);
newCallable
: 可调用对象arg_list
:参数列表,对应callable的参数
当我们调用newCallable的时候,newCallable会调用Callable,并传递给他arg_list
bind的参数
arg_list中的参数,包含形为_n
的参数名字。这些参数是占位符,表示传递给newCallable
的参数位置。
数字n表示生成的可调用对象中参数的位置: _1为newCallable的第一个参数,以此类推。
名字_n都定义在名为placeholders的命名空间。所以在使用的时候需要在前面加入这么一行:
using namespace std::placeholders;
关于占位符和原本函数参数顺序的深究:
参数列表中的_n: 表示为传递给newCallable的参数个数与对应位置(按照n值的顺序)
参数列表本身参数的顺序,表示callable传入的参数
举个例子:
auto g = bind(f, a, b, _2, c, _1);
其中callable函数f有五个参数,分别按照{a, b, _2, c, _1}的顺序传入
bind后的NewCallable函数,有两个参数,分别是{_1, _2},对应f中的第五个和第三个参数。
当我们调用g的时候,第一个参数实际被传到f的最后一个参数。
绑定引用参数
因为除了占位符外其他的参数,bind函数都是按照拷贝的方式返回到bind的可调用对象中。
但是,有时候我们希望引用方式传递参数,或者,有些参数类型无法使用拷贝,比如iostream
实现方法
使用标准库ref函数
- 定义在头文件functional中
- 函数ref返回一个对象,包含给定的引用。
举个例子:
// bind的源函数
ostream &print(ostream &os, const string &s, char c){
return os << s << c;
}
// 使用os的引用
for_each(words.begin(), words.end(), bind(print, ref(os), _1, ' '));