《C++ Primer5》P354
定义
- 函数模板 bind 生成 f 的转发调用包装器,调用此包装器等价于以一些绑定到 args 的参数调用 f
template< class F, class... Args >
bind( F&& f, Args&&... args );
template< class R, class F, class... Args >
bind( F&& f, Args&&... args );
参数
- f - 可调用 (Callable) 对象(函数对象、指向函数指针、到函数引用、指向成员函数指针或指向数据成员指针)
- args - 要绑定的参数列表,未绑定参数为命名空间 std::placeholders 的占位符 _1, _2, _3… 所替换
形式
- 调用bind的一般形式为:
auto newCallable = bind(callable, arg_list);
- 可将bind函数看作一个通用的函数适配器,它接受一个可调用对象,生成一个新的可调用对象来适应原对象的参数列表
- 当调用 newCallable 时,newCallable 会调用 callable ,并传递给它 arg_list 中的参数
- arg_list 中的中包含形如 _n 的“占位符”,它们表示 newCallable 的参数,占据了传递给 newCallable的参数的"位置"
- 数值n表示生成的可调用对象中参数的位置: _1 为 newCallable 的第一个参数,以此类推。
示例
例1:
auto check6 = bind(check_size, _1 ,6);//只有一个占位符,表示check6只接受单一参数
string s = "hello";
bool b1 = check6(s);//check6(s)会调用check_size(s,6)
例2:
auto g = bind(f,a,b,_2,c,_1);//g是一个有两个参数的可调用对象, f为实际工作函数
//传递给g的参数按位置绑定到占位符
//对g的调用会调用f,用g的参数代替占位符
g(X,Y)
f(a,b,Y,c,X)
例3:
#include <random>
#include <iostream>
#include <memory>
#include <functional>
void f(int n1, int n2, int n3, const int& n4, int n5)
{
std::cout << n1 << ' ' << n2 << ' ' << n3 << ' ' << n4 << ' ' << n5 << '\n';
}
int g(int n1)
{
return n1;
}
struct Foo {
void print_sum(int n1, int n2)
{
std::cout << n1+n2 << '\n';
}
int data = 10;
};
int main()
{
using namespace std::placeholders; // 对于 _1, _2, _3...
// 演示参数重排序和按引用传递
int n = 7;
// ( _1 与 _2 来自 std::placeholders ,并表示将来会传递给 f1 的参数)
auto f1 = std::bind(f, _2, _1, 42, std::cref(n), n);
n = 10;
f1(1, 2, 1001); // 1 为 _1 所绑定, 2 为 _2 所绑定,不使用 1001
// 进行到 f(2, 1, 42, n, 7) 的调用
// 嵌套 bind 子表达式共享占位符
auto f2 = std::bind(f, _3, std::bind(g, _3), _3, 4, 5);
f2(10, 11, 12); // 进行到 f(12, g(12), 12, 4, 5); 的调用
// 常见使用情况:以分布绑定 RNG
std::default_random_engine e;
std::uniform_int_distribution<> d(0, 10);
std::function<int()> rnd = std::bind(d, e); // e 的一个副本存储于 rnd
for(int n=0; n<10; ++n)
std::cout << rnd() << ' ';
std::cout << '\n';
// 绑定指向成员函数指针
Foo foo;
auto f3 = std::bind(&Foo::print_sum, &foo, 95, _1);
f3(5);
// 绑定指向数据成员指针
auto f4 = std::bind(&Foo::data, _1);
std::cout << f4(foo) << '\n';
// 智能指针亦能用于调用被引用对象的成员
std::cout << f4(std::make_shared<Foo>(foo)) << '\n'
<< f4(std::make_unique<Foo>(foo)) << '\n';
}
//输出:
2 1 42 10 7
12 12 12 4 5
1 5 0 2 0 8 2 2 10 8
100
10
10
10