Namespaces
Variants

std:: bind

From cppreference.net
Utilities library
Function objects
Function invocation
(C++17) (C++23)
Identity function object
(C++20)
Old binders and adaptors
( until C++17* )
( until C++17* )
( until C++17* )
( until C++17* )
( until C++17* ) ( until C++17* ) ( until C++17* ) ( until C++17* )
( until C++20* )
( until C++20* )
( until C++17* ) ( until C++17* )
( until C++17* ) ( until C++17* )

( until C++17* )
( until C++17* ) ( until C++17* ) ( until C++17* ) ( until C++17* )
( until C++20* )
( until C++20* )
定义于头文件 <functional>
template < class F, class ... Args >
/* 未指定类型 */ bind ( F && f, Args && ... args ) ;
(1) (C++11 起)
(C++20 起为 constexpr)
template < class R, class F, class ... Args >
/* 未指定类型 */ bind ( F && f, Args && ... args ) ;
(2) (C++11 起)
(C++20 起为 constexpr)

函数模板 std::bind 会为 f 生成一个转发调用包装器。调用该包装器等效于将 f 的部分参数 绑定 args 后调用该函数。

如果 std:: is_constructible < std:: decay < F > :: type , F > :: value false ,或者对于 Args 中的任意类型 Arg_i std:: is_constructible < std:: decay < Arg_i > :: type , Arg_i > :: value false ,则程序非良构。

如果 std:: decay < Ti > :: type Args 中的任何类型不满足 可移动构造 可析构 要求,则行为未定义。

目录

参数

f - 可调用对象(函数对象、函数指针、函数引用、成员函数指针或数据成员指针),将被绑定到某些参数
args - 要绑定的参数列表,未绑定的参数由命名空间 std::placeholders 中的占位符 _1 _2 _3 ... 替换

返回值

一个未指定类型 T 的函数对象 g ,满足 std:: is_bind_expression < T > :: value true 。它具有以下成员:

std::bind 返回类型

成员对象

std::bind 的返回类型持有一个类型为 std:: decay < F > :: type 的成员对象,该对象由 std:: forward < F > ( f ) 构造而来,并为每个 args... 持有一个类型为 std:: decay < Arg_i > :: type 的对象,这些对象类似地由 std:: forward < Arg_i > ( arg_i ) 构造。

构造函数

如果 std::bind 返回类型的所有成员对象(如上所述)均为可复制构造,则该类型为 可复制构造 ;否则为 可移动构造 。该类型定义了以下成员:

成员类型 result_type

1) (C++17起弃用) F 为函数指针或成员函数指针,则 result_type F 的返回类型。若 F 为具有嵌套类型定义 result_type 的类类型,则 result_type F::result_type 。否则不定义 result_type
2) (C++17起弃用) result_type 严格为 R
(C++20前)

成员函数 operator()

当在函数调用表达式 g ( u1, u2, ... uM ) 中调用 g 时,会执行存储对象的调用,如同通过

1) INVOKE ( fd, std:: forward < V1 > ( v1 ) , std:: forward < V2 > ( v2 ) , ..., std:: forward < VN > ( vN ) ) ,或
2) INVOKE<R> ( fd, std:: forward < V1 > ( v1 ) , std:: forward < V2 > ( v2 ) , ..., std:: forward < VN > ( vN ) )

其中 fd 是类型为 std:: decay < F > :: type 的值,绑定参数 v1 , v2 , ..., vN 的值和类型按照 下文 规定确定。

如果在调用 g ( ) 时提供的某些参数未被 g 中存储的任何占位符匹配,则未使用的参数会被求值并丢弃。

当且仅当底层的 INVOKE 操作不抛出异常 或是常量子表达式 (C++20起) 时,对 operator ( ) 的调用才 不抛出异常 operator ( ) 仅在 INVOKE 操作作为未求值操作数时格式正确的情况下参与重载决议。

如果 g 具有 volatile 限定,则程序非良构。

如果对于任何可能的 w1 , w2 , ..., wN 值, INVOKE ( fd, w1, w2, ..., wN ) 永远不能是合法表达式,则行为未定义。

绑定参数

对于每个存储的参数 arg_i ,在 INVOKE INVOKE<R> 操作中对应的绑定参数 v_i 按以下方式确定:

情形 1:reference wrappers

如果 arg_i 的类型是 std:: reference_wrapper < T > (例如,在初始调用 std::bind 时使用了 std::ref std::cref ),那么 v_i 就是 arg_i. get ( ) ,其类型 V_i T& :存储的参数通过引用传递给被调用的函数对象。

情形 2:绑定表达式

如果 arg_i 的类型 T 满足 std:: is_bind_expression < T > :: value true (例如另一个 std::bind 表达式被直接传入初始的 std::bind 调用),则 std::bind 会执行函数组合:此时不会传递绑定子表达式返回的函数对象,而是立即调用该子表达式,并将其返回值传递给外层的可调用对象。如果绑定子表达式包含任何占位符参数,这些参数会与外层绑定共享(从 u1 , u2 , ... 中选取)。具体而言, v_i arg_i ( std:: forward < Uj > ( uj ) ... ) ,其类型 V_i std:: result_of < T cv  & ( Uj && ... ) > :: type && (C++17 前) std:: invoke_result_t < T cv  & , Uj && ... > && (C++17 起) (cv 限定符与 g 相同)。

情形3:placeholders

如果 arg_i 的类型为 T ,且满足 std:: is_placeholder < T > :: value 不为 0 (即初始调用 std::bind 时使用了占位符如 std::placeholders::_1, _2, _3, ... 作为参数),则会将占位符指示的参数( _1 对应 u1 _2 对应 u2 等)传递给可调用对象:此时 v_i std:: forward < Uj > ( uj ) ,其类型 V_i Uj&&

情形 4:普通参数

否则, arg_i 将以左值参数的形式传递给可调用对象: v_i 直接是 arg_i ,其类型 V_i T cv  & ,其中 cv g 具有相同的 cv 限定符。

异常

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

注释

Callable 中所述,当调用指向非静态成员函数的指针或指向非静态数据成员的指针时,第一个参数必须是引用或指针(可能包括智能指针,例如 std::shared_ptr std::unique_ptr ),指向将要访问其成员的对象。

传递给 bind 的参数会被复制或移动,除非使用 std::ref std::cref 包装,否则永远不会通过引用传递。

同一绑定表达式中的重复占位符(例如多个 _1 )是允许的,但仅当对应参数( u1 )为左值或不可移动右值时,结果才有明确定义。

示例

#include <functional>
#include <iostream>
#include <memory>
#include <random>
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;  // for _1, _2, _3...
    std::cout << "1) 参数重排序和按引用传递: ";
    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)
    std::cout << "2) 使用 lambda 实现相同效果: ";
    n = 7;
    auto lambda = [&ncref = n, n](auto a, auto b, auto /*unused*/)
    {
        f(b, 42, a, ncref, n);
    };
    n = 10;
    lambda(1, 2, 1001); // 等同于调用 f1(1, 2, 1001)
    std::cout << "3) 嵌套 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);
    std::cout << "4) 将 RNG 与分布绑定: ";
    std::default_random_engine e;
    std::uniform_int_distribution<> d(0, 10);
    auto rnd = std::bind(d, e); // e 的副本存储在 rnd 中
    for (int n = 0; n < 10; ++n)
        std::cout << rnd() << ' ';
    std::cout << '\n';
    std::cout << "5) 绑定到成员函数指针: ";
    Foo foo;
    auto f3 = std::bind(&Foo::print_sum, &foo, 95, _1);
    f3(5);
    std::cout << "6) 绑定到成员函数的 mem_fn: ";
    auto ptr_to_print_sum = std::mem_fn(&Foo::print_sum);
    auto f4 = std::bind(ptr_to_print_sum, &foo, 95, _1);
    f4(5);
    std::cout << "7) 绑定到数据成员指针: ";
    auto f5 = std::bind(&Foo::data, _1);
    std::cout << f5(foo) << '\n';
    std::cout << "8) 绑定到数据成员的 mem_fn: ";
    auto ptr_to_data = std::mem_fn(&Foo::data);
    auto f6 = std::bind(ptr_to_data, _1);
    std::cout</

缺陷报告

下列行为变更缺陷报告被追溯应用于先前发布的C++标准。

缺陷报告 应用于 发布时行为 正确行为
LWG 2021 C++11 1. 绑定的参数
未转发至 fd
2. 在情况2中, V_i 的类型为
std:: result_of < T cv  ( Uj... ) > :: type
1. 已转发
2. 更改为
std:: result_of < T cv  & ( Uj && ... ) > :: type &&

参见

(C++20) (C++23)
将可变数量的参数按顺序绑定到函数对象
(函数模板)
std::bind 表达式中未绑定参数的占位符
(常量)
(C++11)
从成员指针创建函数对象
(函数模板)