C++11新特性——bind和function

      版权声明:本文为灿哥哥http://blog.csdn.net/caoshangpa原创文章,转载请标明出处。           https://blog.csdn.net/caoshangpa/article/details/79173351        </div>
        <link rel="stylesheet" href="https://csdnimg.cn/release/phoenix/template/css/ck_htmledit_views-f57960eb32.css">
                          <link rel="stylesheet" href="https://csdnimg.cn/release/phoenix/template/css/ck_htmledit_views-f57960eb32.css">
      <div class="htmledit_views" id="content_views">

一.std::bind

bind是这样一种机制,它可以将参数绑定于可调用对象,产生一个新的可调用实体,这种机制在函数回调时颇为有用。C++98中,有两个函数bind1st和bind2nd,它们分别用来绑定functor的第一个和第二个参数,都只能绑定一个参数。C++98提供的这些特性已经由于C++11的到来而过时,由于各种限制,我们经常使用bind而非bind1st和bind2nd。在C++11标准库中,它们均在functional头文件中。而C++STL很大一部分由Boost库扩充,STL中的shared_ptr等智能指针,bind及function都是由Boost库引入。在写代码过程中,要养成使用bind,function,lambda和智能指针的习惯,它们非常强大简洁实用。

1.过时的bind1st和bind2nd
bind1st(op, arg) :op(arg, param) 
bind2nd(op, arg) :op(param, arg)

  1. vector<int> coll {1, 2, 3, 4, 5, 11, 22, 5, 12};
  2. // 查找第一个元素值大于10的元素
  3. std::find_if(coll.begin(), coll.end(), // 范围
  4. std::bind2nd(std::greater<int>(), 10));// 将10绑定到第二个参数,也就是 ......大于10
  5. // 查找元素值大于10的元素的个数
  6. int _count = count_if(coll.begin(), coll.end(), // 范围
  7. std::bind1st(less<int>(), 10));// 将10绑定到第一个参数,也就是10小于......
2. C++11中的std::bind

  1. //function object内部调用plus<>(也就是operator+),以占位符(placeholders)_1为第一个参数,
  2. //以10为第二个参数,占位符_1表示实际传入此表达式的第一实参,返回“实参+10”的结果值
  3. auto plus10 = std::bind(std::plus<int> (), std::placeholders::_1, 10);
  4. std::cout << plus10(7) << std::endl;// 输出17
  1. // (x + 10)*2,下面的代码中x=7
  2. std::bind(std::multiplies<int>(),
  3. std::bind(std::plus<int>(), std::placeholders::_1, 10),// i+10
  4. 2)(7);
注意:上面所用的less<int>(),greater<int>()以及plus<int>()等都是C++预定义的Function Object。因此我们可以知道,bind可以把参数绑定到“函数对象”上。除此之外,bind()还可以把参数绑定到普通函数、类成员函数、甚至数据成员等。
3. 使用std::bind要注意的地方
(1)bind预先绑定的参数需要传具体的变量或值进去,对于预先绑定的参数,是pass-by-value的。除非该参数被std::ref或者std::cref包装,才pass-by-reference。

(2)对于不事先绑定的参数,需要传std::placeholders进去,从_1开始,依次递增。placeholder是pass-by-reference的;
(3)bind的返回值是可调用实体,可以直接赋给std::function对象; 
(4)对于绑定的指针、引用类型的参数,使用者需要保证在可调用实体调用之前,这些参数是可用的;
(5)类的this可以通过对象或者指针来绑定

4.一个例子

  1. #include <iostream>
  2. #include <memory>
  3. #include <functional>
  4. void f(int n1, int n2, int n3, const int& n4, int n5)
  5. {
  6. std::cout << n1 << ' ' << n2 << ' ' << n3 << ' ' << n4 << ' ' << n5 << '\n';
  7. }
  8. int g(int n1)
  9. {
  10. return n1;
  11. }
  12. struct Foo {
  13. void print_sum(int n1, int n2)
  14. {
  15. std::cout << n1+n2 << '\n';
  16. }
  17. int data = 10;
  18. };
  19. int main()
  20. {
  21. using namespace std::placeholders; // for _1, _2, _3...
  22. // demonstrates argument reordering and pass-by-reference
  23. int n = 7;
  24. // (_1 and _2 are from std::placeholders, and represent future
  25. // arguments that will be passed to f1)
  26. auto f1 = std::bind(f, _2, _1, 42, std::cref(n), n);
  27. n = 10;
  28. f1(1, 2, 1001); // 1 is bound by _1, 2 is bound by _2, 1001 is unused
  29. // makes a call to f(2, 1, 42, n, 7)
  30. // nested bind subexpressions share the placeholders
  31. auto f2 = std::bind(f, _3, std::bind(g, _3), _3, 4, 5);
  32. f2(10, 11, 12); // makes a call to f(12, g(12), 12, 4, 5);
  33. // bind to a pointer to member function
  34. Foo foo;
  35. auto f3 = std::bind(&Foo::print_sum, &foo, 95, _1);
  36. f3(5);
  37. // bind to a pointer to data member
  38. auto f4 = std::bind(&Foo::data, _1);
  39. std::cout << f4(foo) << '\n';
  40. }
输出结果;

  1. 2 1 42 10 7
  2. 12 12 12 4 5
  3. 100
  4. 10
二.std::function

类模版std::function是一种通用、多态的函数封装。std::function的实例可以对任何可以调用的目标实体进行存储、复制、和调用操作,这些目标实体包括普通函数、Lambda表达式、bind表达式、函数指针以及其它函数对象,。std::function对象是对C++中现有的可调用实体的一种类型安全的包装(我们知道像函数指针这类可调用实体,是类型不安全的)。

最简单的理解就是:
通过std::function对C++中各种可调用实体(普通函数、Lambda表达式、函数指针、以及其它函数对象等)的封装,形成一个新的可调用的std::function对象;让我们不再纠结那么多的可调用实体。

  1. #include <functional>
  2. #include <iostream>
  3. struct Foo {
  4. Foo(int num) : num_(num) {}
  5. void print_add(int i) const { std::cout << num_+i << '\n'; }
  6. int num_;
  7. };
  8. void print_num(int i)
  9. {
  10. std::cout << i << '\n';
  11. }
  12. struct PrintNum {
  13. void operator()(int i) const
  14. {
  15. std::cout << i << '\n';
  16. }
  17. };
  18. int main()
  19. {
  20. // store a free function
  21. std::function<void(int)> f_display = print_num;
  22. f_display(-9);
  23. // store a lambda
  24. std::function<void()> f_display_42 = []() { print_num(42); };
  25. f_display_42();
  26. // store the result of a call to std::bind
  27. std::function<void()> f_display_31337 = std::bind(print_num, 31337);
  28. f_display_31337();
  29. // store a call to a member function
  30. std::function<void(const Foo&, int)> f_add_display = &Foo::print_add;
  31. const Foo foo(314159);
  32. f_add_display(foo, 1);
  33. f_add_display(314159, 1);
  34. // store a call to a data member accessor
  35. std::function<int(Foo const&)> f_num = &Foo::num_;
  36. std::cout << "num_: " << f_num(foo) << '\n';
  37. // store a call to a member function and object
  38. using std::placeholders::_1;
  39. std::function<void(int)> f_add_display2 = std::bind( &Foo::print_add, foo, _1 );
  40. f_add_display2(2);
  41. // store a call to a member function and object ptr
  42. std::function<void(int)> f_add_display3 = std::bind( &Foo::print_add, &foo, _1 );
  43. f_add_display3(3);
  44. // store a call to a function object
  45. std::function<void(int)> f_display_obj = PrintNum();
  46. f_display_obj(18);
  47. }
输出结果:

  1. -9
  2. 42
  3. 31337
  4. 314160
  5. 314160
  6. num_: 314159
  7. 314161
  8. 314162
  9. 18

参考链接:http://en.cppreference.com/w/cpp/utility/functional/function


posted @ 2019-05-19 21:33  unique_ptr  阅读(905)  评论(0编辑  收藏  举报