c++11 特性 std::function 与 std::bind

来源:互联网 发布:矩阵分解优化问题 编辑:程序博客网 时间:2024/05/17 23:39

~~~~我的生活,我的点点滴滴!!


std::function 和 std::bind



标准库函数bind()和function()定义于头文件<functional>中(该头文件还包括许多其他函数对象),用于处理函数及函数参数。类模版 std::function 是一种通用、多态的函数封装。


function

std::function 的实例可以对任何可以调用的 目标 进行存储、复制、和调用操作,这些目标包括函数、lambda 表达式、绑定表达式、以及其它函数对象等。

看下面的例子:

#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';} int main(){    // 保存自由函数    std::function<void(int)> f_display = print_num;    f_display(-9);     // 保存 lambda 表达式    std::function<void()> f_display_42 = []() { print_num(42); };    f_display_42();     // 保存 std::bind 的结果    std::function<void()> f_display_31337 = std::bind(print_num, 31337);    f_display_31337();     // 保存成员函数    std::function<void(const Foo&, int)> f_add_display = &Foo::print_add;    Foo foo(314159);    f_add_display(foo, 1);}


输出:
-9
42
31337
314160


bind

bind()接受一个函数(或者函数对象,或者任何你可以通过”(…)”符号调用的事物),生成一个其有某一个或多个函数参数被“绑定”,

要绑定的参数被复制或移动的,并且永远不会通过引用传递,除非包裹在std::ref或std::cref重复在相同的绑定表达式的占位符(多_1的例子)是允许的,

但结果却只有明确定义,如果相应的参数(u1)是一个左值或不可移动的右值。

#include <random>#include <iostream>#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;     // 传值用引用方式 std::cref(n)    int n = 7;    auto f1 = std::bind(f, _2, _1, 42, std::cref(n), n);    n = 10;// 1 被绑定为_1, 2 被绑定为_2, 1001没用    f1(1, 2, 1001);      // 潜入表达式,可以共享占用符    auto f2 = std::bind(f, _3, std::bind(g, _3), _3, 4, 5);    f2(10, 11, 12);     // 绑定到普通成员函数    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';}

输出:
2 1 42 10 7
12 12 12 4 5
100
10

注:

std::ref()表示传引用

std::cref()表示传不变引用

特别注意:

bind对于不事先绑定的参数,通过std::placeholders传递的参数是通过引用传递的

bind对于预先绑定的函数参数是通过值传递的

看下面一段代码就知道了

#include <iostream>using namespace std;class A{public:    void fun_3(int k,int m)    {        cout<<k<<" "<<m<<endl;    }}; void fun(int x,int y,int z){    cout<<x<<"  "<<y<<"  "<<z<<endl;} void fun_2(int &a,int &b){    a++;    b++;    cout<<a<<"  "<<b<<endl;} int main(int argc, const char * argv[]){    auto f1 = bind(fun,1,2,3); //表示绑定函数 fun 的第一,二,三个参数值为: 1 2 3    f1(); //print:1  2  3         auto f2 = bind(fun, placeholders::_1,placeholders::_2,3);    //表示绑定函数 fun 的第三个参数为 3,而fun 的第一,二个参数分别有调用 f2 的第一,二个参数指定    f2(1,2);//print:1  2  3         auto f3 = bind(fun,placeholders::_2,placeholders::_1,3);    //表示绑定函数 fun 的第三个参数为 3,而fun 的第一,二个参数分别有调用 f3 的第二,一个参数指定    //注意: f2  和  f3 的区别。    f3(1,2);//print:2  1  3              int n = 2;    int m = 3;         auto f4 = bind(fun_2, n,placeholders::_1);    f4(m); //print:3  4     cout<<m<<endl;//print:4  说明:bind对于不事先绑定的参数,通过std::placeholders传递的参数是通过引用传递的    cout<<n<<endl;//print:2  说明:bind对于预先绑定的函数参数是通过值传递的              A a;    auto f5 = bind(&A::fun_3, a,placeholders::_1,placeholders::_2);    f5(10,20);//print:10 20         std::function<void(int,int)> fc = std::bind(&A::fun_3, a,std::placeholders::_1,std::placeholders::_2);    fc(10,20);//print:10 20         return 0;}


看一段代码:

#include <functional>#include <iostream> void f(int& n1, int& n2, const int& n3){    std::cout << "In function: " << n1 << ' ' << n2 << ' ' << n3 << '\n';    ++n1; // increments the copy of n1 stored in the function object    ++n2; // increments the main()'s n2    // ++n3; // compile error} int main(){    int n1 = 1, n2 = 2, n3 = 3;    std::function<void()> bound_f = std::bind(f, n1, std::ref(n2), std::cref(n3));    n1 = 10;    n2 = 11;    n3 = 12;    std::cout << "Before function: " << n1 << ' ' << n2 << ' ' << n3 << '\n';    bound_f();    std::cout << "After function: " << n1 << ' ' << n2 << ' ' << n3 << '\n';}

输出:

Before function: 10 11 12In function: 1 11 12After function: 10 12 12
从上面看出,其实绑定时,按值已经传递好了,是不会在更改的,但是如果使用了ref与cref,他们按地址传递,就能更改其值。

参照 c++ 官网 http://zh.cppreference.com/w/cpp/utility/functional/

如果 在最后面加上 function (http://zh.cppreference.com/w/cpp/utility/functional/function)他就会跳转到function说明

如果 加上bind 就会跳转到bind说明。

0 0