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

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


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 12
In function: 1 11 12
After 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
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值