名稱空間
變體
操作

std::bind

來自 cppreference.com
 
 
 
函式物件
函式呼叫
(C++17)(C++23)
恆等函式物件
(C++20)
透明運算子包裝器
(C++14)
(C++14)
(C++14)
(C++14)  
(C++14)
(C++14)
(C++14)
(C++14)
(C++14)
(C++14)
(C++14)
(C++14)
(C++14)

舊繫結器和介面卡
(直到 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 >
/* 未指定 */ 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::bindf 生成一個轉發呼叫包裝器。呼叫此包裝器等同於以其部分引數繫結args 的方式呼叫 f

std::is_constructible<std::decay<F>::type, F>::valuefalse,或對於 Args 中的任何型別 Arg_istd::is_constructible<std::decay<Arg_i>::type, Arg_i>::valuefalse,則程式非良構。

std::decay<Ti>::typeArgs 中的任何型別不是可移動構造 (MoveConstructible)可析構 (Destructible),則行為未定義。

目錄

[編輯] 引數

f - 可呼叫 (Callable) 物件(函式物件、函式指標、函式引用、成員函式指標或資料成員指標),它將被繫結到某些引數
args - 要繫結的引數列表,未繫結的引數將替換為名稱空間 std::placeholders佔位符 _1_2_3...

[編輯] 返回值

一個未指定型別 T 的函式物件 g,對於它 std::is_bind_expression<T>::valuetrue。它擁有以下成員

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 的返回型別是可複製構造 (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()

當在函式呼叫表示式 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 中儲存的任何佔位符都不匹配,則未使用的引數會被求值並丟棄。

operator() 的呼叫是不丟擲異常的 或是常量子表示式(C++20 起),當且僅當底層 INVOKE 操作也是如此。operator() 僅在 INVOKE 操作作為未求值運算元時良構時才參與過載決議。

gvolatile 限定的,則程式非良構。

INVOKE(fd, w1, w2, ..., wN) 對於任何可能的值 w1, w2, ..., wN 均不能是有效表示式,則行為未定義。

[編輯] 繫結引數

對於每個儲存的引數 arg_i,在 INVOKEINVOKE<R> 操作中對應的繫結引數 v_i 按以下方式確定:

[編輯] 情況 1:引用包裝器

arg_i 的型別為 std::reference_wrapper<T>(例如,在對 std::bind 的初始呼叫中使用了 std::refstd::cref),則 v_iarg_i.get(),其型別 V_iT&:儲存的引數透過引用傳遞給被呼叫的函式物件。

[編輯] 情況 2:繫結表示式

arg_i 的型別為 T,對於它 std::is_bind_expression<T>::valuetrue(例如,另一個 std::bind 表示式直接傳遞給對 std::bind 的初始呼叫),則 std::bind 執行函式組合:不是傳遞繫結子表示式將返回的函式物件,而是急切地呼叫子表示式,並將其返回值傳遞給外部可呼叫物件。若繫結子表示式有任何佔位符引數,它們與外部繫結共享(從 u1, u2, ... 中取出)。具體來說,v_iarg_i(std::forward<Uj>(uj)...),其型別 V_istd::result_of<T cv &(Uj&&...)>::type&&(直到 C++17)std::invoke_result_t<T cv &, Uj&&...>&&(C++17 起)(cv-限定與 g 的相同)。

[編輯] 情況 3:佔位符

arg_i 的型別為 T,對於它 std::is_placeholder<T>::value 不是 0(這意味著,佔位符如 std::placeholders::_1, _2, _3, ... 被用作對 std::bind 的初始呼叫的引數),則佔位符指示的引數(_1 對應 u1_2 對應 u2,等等)被傳遞給可呼叫物件:v_istd::forward<Uj>(uj),其型別 V_iUj&&

[編輯] 情況 4:普通引數

否則,arg_i 作為左值引數傳遞給可呼叫物件:v_i 簡單地是 arg_i,其型別 V_iT cv &,其中 cvg 的 cv-限定相同。

[編輯] 異常

僅當從 std::forward<F>(f) 構造 std::decay<F>::type 丟擲異常,或從對應的 std::forward<Arg_i>(arg_i) 構造 std::decay<Arg_i>::type 的任何建構函式丟擲異常時才丟擲,其中 Arg_i 是第 i 個型別,arg_iArgs... args 中的第 i 個引數。

[編輯] 註記

可呼叫 (Callable) 中所述,當呼叫非靜態成員函式指標或非靜態資料成員指標時,第一個引數必須是對其成員將被訪問的物件的引用或指標(包括可能的智慧指標,如 std::shared_ptrstd::unique_ptr)。

繫結到 bind 的引數被複制或移動,並且除非用 std::refstd::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) argument reordering and pass-by-reference: ";
    int n = 7;
    // (_1 and _2 are from std::placeholders, and represent future
    // arguments that will be passed to f1)
    auto f1 = std::bind(f, _2, 42, _1, std::cref(n), n);
    n = 10;
    f1(1, 2, 1001); // 1 is bound by _1, 2 is bound by _2, 1001 is unused
                    // makes a call to f(2, 42, 1, n, 7)
 
    std::cout << "2) achieving the same effect using a 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); // same as a call to f1(1, 2, 1001)
 
    std::cout << "3) nested bind subexpressions share the placeholders: ";
    auto f2 = std::bind(f, _3, std::bind(g, _3), _3, 4, 5);
    f2(10, 11, 12); // makes a call to f(12, g(12), 12, 4, 5);
 
    std::cout << "4) bind a RNG with a distribution: ";
    std::default_random_engine e;
    std::uniform_int_distribution<> d(0, 10);
    auto rnd = std::bind(d, e); // a copy of e is stored in rnd
    for (int n = 0; n < 10; ++n)
        std::cout << rnd() << ' ';
    std::cout << '\n';
 
    std::cout << "5) bind to a pointer to member function: ";
    Foo foo;
    auto f3 = std::bind(&Foo::print_sum, &foo, 95, _1);
    f3(5);
 
    std::cout << "6) bind to a mem_fn that is a pointer to member function: ";
    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) bind to a pointer to data member: ";
    auto f5 = std::bind(&Foo::data, _1);
    std::cout << f5(foo) << '\n';
 
    std::cout << "8) bind to a mem_fn that is a pointer to data member: ";
    auto ptr_to_data = std::mem_fn(&Foo::data);
    auto f6 = std::bind(ptr_to_data, _1);
    std::cout << f6(foo) << '\n';
 
    std::cout << "9) use smart pointers to call members of the referenced objects: ";
    std::cout << f6(std::make_shared<Foo>(foo)) << ' '
              << f6(std::make_unique<Foo>(foo)) << '\n';
}

輸出

1) argument reordering and pass-by-reference: 2 42 1 10 7
2) achieving the same effect using a lambda: 2 42 1 10 7
3) nested bind subexpressions share the placeholders: 12 12 12 4 5
4) bind a RNG with a distribution: 0 1 8 5 5 2 0 7 7 10 
5) bind to a pointer to member function: 100
6) bind to a mem_fn that is a pointer to member function: 100
7) bind to a pointer to data member: 10
8) bind to a mem_fn that is a pointer to data member: 10
9) use smart pointers to call members of the referenced objects: 10 10

[編輯] 缺陷報告

下列更改行為的缺陷報告追溯地應用於以前出版的 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)
從指向成員的指標建立函式物件
(函式模板) [編輯]