std::bind

来自cppreference.com
< cpp‎ | utility‎ | functional
 
 
 
函数对象
函数包装
(C++11)
(C++11)
部分函数应用
bind
(C++11)
(C++20)
函数调用
(C++17)
恒等函数对象
(C++20)
引用包装
(C++11)(C++11)
运算符包装
取反器
(C++17)
搜索器
有制约的比较器
旧绑定器与适配器
(C++17 前)
(C++17 前)
(C++17 前)
(C++17 前)
(C++17 前)(C++17 前)(C++17 前)(C++17 前)
(C++20 前)
(C++20 前)
(C++17 前)(C++17 前)
(C++17 前)(C++17 前)

(C++17 前)
(C++17 前)(C++17 前)(C++17 前)(C++17 前)
(C++20 前)
(C++20 前)
 
定义于头文件 <functional>
template< class F, class... Args >
/*unspecified*/ bind( F&& f, Args&&... args );
(1) (C++11 起)
template< class R, class F, class... Args >
/*unspecified*/ bind( F&& f, Args&&... args );
(2) (C++11 起)

函数模板 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) 。类型定义下列成员:

成员类型 result_type

1) (C++17 中弃用)F 是指向函数或指向成员函数指针,则 result_typeF 的返回类型。若 F 是有嵌套 typedef result_type 的类类型,则 result_typeF::result_type 。否则不定义 result_type

2) (C++17 中弃用) result_type 准确地为 R

(C++20 前)

成员函数 operator()

给定从先前到 bind 调用获得的对象 g ,从函数调用表达式 g(u1, u2, ... uM) 调用它时,发生被存储对象的调用,如同以 std::invoke(fd, std::forward<V1>(v1), std::forward<V2>(v2), ..., std::forward<VN>(vN)) ,其中 fdstd::decay_t<F> 类型值,受绑定 v1, v2, ..., vN 参数的值和类型按以下方式确定。

  • 若存储的参数 arg 拥有类型 std::reference_wrapper<T> (例如,在起始的到 bind 调用中使用了 std::refstd::cref ),则上述 std::invoke 调用中的 vnarg.get() 且同一调用中的类型 VnT& :存储的参数按引用传递进入被调用的函数对象。
  • 若存储的参数 arg 拥有类型 T 并满足 std::is_bind_expression<T>::value == true (例如,直接传递到起始的对 bind 调用的另一 bind 表达式),则 bind 进行函数组合:不是传递该 bind 子表达式将返回的函数对象,而是饥渴地调用该子表达式,并将其返回值传递给外层可调用对象。若 bind 子表达式拥有任何占位符参数,则将它们与外层 bind 共享(从 u1, u2, ... 中选出)。特别是,上述 std::invoke 调用中的参数 vnarg(std::forward<Uj>(uj)...) 而同一调用中的类型 Vnstd::result_of_t<T cv &(Uj&&...)>&& ( cv 限定与 g 的相同)。
  • 若存储的参数 arg 拥有类型 T 并满足 std::is_placeholder<T>::value != 0 (表示以如 std::placeholders::_1, _2, _3, ... 的占位符为到 bind 初始调用的参数),则将占位符所指示的参数( _1u1_2u2 等)传递给可调用对象:上述 std::invoke 调用中的参数 vnstd::forward<Uj>(uj) 而同一调用中对应类型 VnUj&&
  • 否则,普通的存储参数 arg 作为左值参数传递给:上述 std::invoke 调用中的参数 vn 单纯地是 arg 且对应类型 VnT cv & ,其中 cv 是与 g 相同的 cv 限定。

若提供于到 g() 调用的一些参数不匹配存储于 g 的任何占位符,则求值并忽略未使用的参数。

g 为 volatile 限定(即其 cv 限定符是 volatileconst volatile ),则行为未定义。

异常

仅若从 std::forward<F>(f) 构造 std::decay<F>::type 抛出,或从 std::forward<Arg_i>(arg_i) 构造对应的任何 std::decay<Arg_i>::type 抛出才抛出异常,其中 Arg_iArgs... args 中第 i 个类型,而 arg_i 是第 i 个参数。

注意

可调用 (Callable) 中描述,调用指向非静态成员函数指针或指向非静态数据成员指针时,首参数必须是引用或指针(可以包含智能指针,如 std::shared_ptrstd::unique_ptr),指向将访问其成员的对象。

到 bind 的参数被复制或移动,而且决不按引用传递,除非包装于 std::refstd::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

参阅

按顺序绑定一定数量的参数到函数对象
(函数模板)
用作 std::bind 表达式中的未绑定实参的占位符
(常量)
(C++11)
从成员指针创建出函数对象
(函数模板)