std::bind
定义于头文件 <functional>
|
||
(1) | ||
template< class F, class... Args > /*unspecified*/ bind( F&& f, Args&&... args ); |
(C++11 起) (C++20 前) |
|
template< class F, class... Args > constexpr /*unspecified*/ bind( F&& f, Args&&... args ); |
(C++20 起) | |
(2) | ||
template< class R, class F, class... Args > /*unspecified*/ bind( F&& f, Args&&... args ); |
(C++11 起) (C++20 前) |
|
template< class R, class F, class... Args > constexpr /*unspecified*/ bind( F&& f, Args&&... args ); |
(C++20 起) | |
函数模板 bind
生成 f
的转发调用包装器。调用此包装器等价于以一些绑定到 args
的参数调用 f
。
参数
f | - | 可调用 (Callable) 对象(函数对象、指向函数指针、到函数引用、指向成员函数指针或指向数据成员指针) |
args | - | 要绑定的参数列表,未绑定参数为命名空间 std::placeholders 的占位符 _1, _2, _3... 所替换
|
返回值
未指定类型 T
的函数对象,满足 std::is_bind_expression<T>::value == true 。它有下列属性:
std::bind 返回类型
成员对象
std::bind
的返回类型保有从 std::forward<F>(f) 构造的 std::decay<F>::type 类型成员对象,和对于每个 args...
类型为 std::decay<Arg_i>::type 的各一个对象,类似地从 std::forward<Arg_i>(arg_i) 构造。
构造函数
若 std::bind
的返回类型的所有成员类型(说明如上)为可复制构造 (CopyConstructible) ,则它为可复制构造 (CopyConstructible) ,否则为可移动构造 (MoveConstructible) 。类型定义下列成员:
成员类型
|
(C++20 前) |
成员函数 operator()
给定从先前到 bind
调用获得的对象 g
,从函数调用表达式 g(u1, u2, ... uM) 调用它时,发生被存储对象的调用,如同以 std::invoke(fd, std::forward<V1>(v1), std::forward<V2>(v2), ..., std::forward<VN>(vN)) ,其中 fd
是 std::decay_t<F> 类型值,受绑定 v1, v2, ..., vN
参数的值和类型按以下方式确定。
- 若存储的参数
arg
拥有类型 std::reference_wrapper<T> (例如,在起始的到bind
调用中使用了 std::ref 或 std::cref ),则上述std::invoke
调用中的vn
是arg.get()
且同一调用中的类型Vn
是T&
:存储的参数按引用传递进入被调用的函数对象。 - 若存储的参数
arg
拥有类型T
并满足 std::is_bind_expression<T>::value == true (例如,直接传递到起始的对bind
调用的另一bind
表达式),则bind
进行函数组合:不是传递该 bind 子表达式将返回的函数对象,而是饥渴地调用该子表达式,并将其返回值传递给外层可调用对象。若 bind 子表达式拥有任何占位符参数,则将它们与外层 bind 共享(从u1, u2, ...
中选出)。特别是,上述std::invoke
调用中的参数vn
是arg(std::forward<Uj>(uj)...)
而同一调用中的类型Vn
是 std::result_of_t<T cv &(Uj&&...)>&& ( cv 限定与g
的相同)。 - 若存储的参数
arg
拥有类型T
并满足 std::is_placeholder<T>::value != 0 (表示以如std::placeholders::_1, _2, _3, ...
的占位符为到bind
初始调用的参数),则将占位符所指示的参数(_1
的u1
、_2
的u2
等)传递给可调用对象:上述std::invoke
调用中的参数vn
是 std::forward<Uj>(uj) 而同一调用中对应类型Vn
是 Uj&& 。 - 否则,普通的存储参数
arg
作为左值参数传递给:上述std::invoke
调用中的参数vn
单纯地是arg
且对应类型Vn
是T cv &
,其中 cv 是与g
相同的 cv 限定。
若提供于到 g()
调用的一些参数不匹配存储于 g
的任何占位符,则求值并忽略未使用的参数。
若 g
为 volatile 限定(即其 cv 限定符是 volatile 或 const volatile ),则行为未定义。
异常
仅若从 std::forward<F>(f) 构造 std::decay<F>::type 抛出,或从 std::forward<Arg_i>(arg_i) 构造对应的任何 std::decay<Arg_i>::type 抛出才抛出异常,其中 Arg_i
是 Args... args
中第 i 个类型,而 arg_i
是第 i 个参数。
注解
如可调用 (Callable) 中描述,调用指向非静态成员函数指针或指向非静态数据成员指针时,首参数必须是引用或指针(可以包含智能指针,如 std::shared_ptr 与 std::unique_ptr),指向将访问其成员的对象。
到 bind 的参数被复制或移动,而且决不按引用传递,除非包装于 std::ref 或 std::cref 。
允许同一 bind 表达式中的多重占位符(例如多个 _1
),但结果仅若对应参数( u1
)是左值或不可移动右值才良好定义。
示例
#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, 42, _1, std::cref(n), n); n = 10; f1(1, 2, 1001); // 1 为 _1 所绑定, 2 为 _2 所绑定,不使用 1001 // 进行到 f(2, 42, 1, 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 42 1 10 7 12 12 12 4 5 1 5 0 2 0 8 2 2 10 8 100 10 10 10
参阅
(C++20) |
按顺序绑定一定数量的参数到函数对象 (函数模板) |
(C++11) |
用作 std::bind 表达式中的未绑定实参的占位符 (常量) |
(C++11) |
从成员指针创建出函数对象 (函数模板) |