1. 程式人生 > >c++ function和bind

c++ function和bind

1+n fault ref args all main tor bound cal

bind

定義在頭文件 functional 裏

template<typename _Func, typename... _BoundArgs>
inline typename
_Bind_helper<__is_socketlike<_Func>::value, _Func, _BoundArgs...>::type
bind(_Func&& __f, _BoundArgs&&... __args)

template<typename _Result, typename _Func, typename... _BoundArgs>
inline
typename _Bindres_helper
<_Result, _Func, _BoundArgs...>::type bind(_Func&& __f, _BoundArgs&&... __args)

函數模板 bind 生成 f 的轉發調用包裝器。調用此包裝器等價於以一些綁定到 args 的參數調用 f 。類似於 python 的 functools.partial

參數 f 表示可調用對象(函數對象、指向函數指針、函數的引用、指向成員函數指針或指向數據成員指針)

參數 __args 表示要綁定的參數列表。未綁定參數使用命名空間 std::placeholders 的占位符 _1, _2, _3...

所替換

需要註意的是:

調用指向非靜態成員函數指針或指向非靜態數據成員指針時,首參數必須是引用或指針(可以包含智能指針,如 std::shared_ptr 與 std::unique_ptr),指向將訪問其成員的對象。

到 bind 的參數被復制或移動,而且決不按引用傳遞,除非包裝於 ref 或 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, _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); // 100 // 綁定指向數據成員指針 auto f4 = std::bind(&Foo::data, _1); std::cout << f4(foo) << \n; // 10 // 智能指針亦能用於調用被引用對象的成員 std::cout << f4(std::make_shared<Foo>(foo)) << \n; // 10 return 0; }

function

定義在頭文件 functional 裏

template<typename _Res, typename... _ArgTypes>
class function<_Res(_ArgTypes...)>

類模板 std::function 是通用多態函數封裝器。 std::function 的實例能存儲、復制及調用任何可回調目標——函數、lambda表達式、bind表達式、其他函數對象,還可以指向成員函數指針和指向數據成員指針。

存儲的可調用對象被稱為 std::function目標。若 std::function 不含目標,則稱它為。調用 std::function目標導致拋出 bad_function_call 異常。

function 滿足可復制構造和可復制賦值。

#include <functional>
#include <iostream>
 
struct Foo {
    Foo(int num) : num_(num) {}
    void print_add(int i) const { std::cout << num_+i << \n; }
    int num_;
};
 
void print_num(int i)
{
    std::cout << i << \n;
}
 
struct PrintNum {
    void operator()(int i) const
    {
        std::cout << i << \n;
    }
};
 
int main()
{
    // 存儲自由函數
    std::function<void(int)> f_display = print_num;
    f_display(-9);      // -9
 
    // 存儲 lambda
    std::function<void()> f_display_42 = []() { print_num(42); };
    f_display_42();     // 42
 
    // 存儲到 std::bind 調用的結果
    std::function<void()> f_display_31337 = std::bind(print_num, 31337);
    f_display_31337();  // 31337
 
    // 存儲到成員函數的調用
    std::function<void(const Foo&, int)> f_add_display = &Foo::print_add;
    const Foo foo(314159);
    f_add_display(foo, 1);      // 314160
    f_add_display(314159, 1);   // 314160
 
    // 存儲到數據成員訪問器的調用
    std::function<int(Foo const&)> f_num = &Foo::num_;
    std::cout << "num_: " << f_num(foo) << \n;    // 314159
 
    // 存儲到成員函數及對象的調用
    using std::placeholders::_1;
    std::function<void(int)> f_add_display2 = std::bind( &Foo::print_add, foo, _1 );
    f_add_display2(2);      // 314161
 
    // 存儲到成員函數和對象指針的調用
    std::function<void(int)> f_add_display3 = std::bind( &Foo::print_add, &foo, _1 );
    f_add_display3(3);      // 314162
 
    // 存儲到函數對象的調用
    std::function<void(int)> f_display_obj = PrintNum();
    f_display_obj(18);      // 18
}

c++ function和bind