C++常用新特性: std::bind && std::function

1. std::function

类模板 std::function 是通用多态函数封装器。 std::function 的实例能存储、复制及调用任何可调用 (Callable) 目标——函数、 lambda 表达式、 bind 表达式或其他函数对象,还有指向成员函数指针和指向数据成员指针。存储的可调用对象被称为 std::function 的目标。若 std::function 不含目标,则称它为空。调用空 std::function 的目标导致抛出 std::bad_function_call 异常。它满足可复制构造 (CopyConstructible) 和可复制赋值 (CopyAssignable) 。若需要与类非静态成员绑定需要与std::bind结合使用。

2. std::bind

C++11起使用std::bind进行函数绑定,它可以绑定普通函数、全局函数、静态函数、类静态函数甚至是类成员函数,std::bind在绑定时可以绑定一部分参数,未绑定的参数使用占位符,在运行时再传入参数,它的返回值是一个函数对象,可以赋值给std::function对象。

std::bind函数定义如下:
template< class F, class… Args >
/unspecified/ bind( F&& f, Args&&… args );
参数:
F: 可调用 (Callable) 对象(函数对象、指向函数指针、到函数引用、指向成员函数指针或指向数据成员指针)
args: 绑定的参数列表,未绑定参数为命名空间 std::placeholders 的占位符 _1, _2, _3… 所替换

注意:
如可调用 (Callable) 中描述,调用指向非静态成员函数指针或指向非静态数据成员指针时,首参数必须是引用或指针(可以包含智能指针,如 std::shared_ptr 与 std::unique_ptr),指向将访问其成员的对象。
到 bind 的参数被复制或移动,而且决不按引用传递,除非包装于 std::ref 或 std::cref 。
允许同一 bind 表达式中的多重占位符(例如多个 _1 ).

3. 使用实例

#include<iostream>
#include<functional>
#include<random>
int Sumfun(int a, int b){
  return a+b;
}
template <typename T>
T Sumfun2(T a, T b){
  return a+b;
}
struct PrintNum{
  void operator()(int num)const{
    std::cout<<"PrintNum: "<<num<<std::endl;
  }
};

class Foo{
public:
  Foo(int num):num_(num){}
  void Print_add(int value)const{
    std::cout<<"Foo Print_add: "<<num_ + value<<std::endl;
  }
  int num_;
};
int main(int argc, char**argv)
{
  ///存储自由函数
  std::function<int(int,int)> fun_sum = Sumfun;
  std::cout<<"sum: "<<fun_sum(1,2)<<std::endl;  ///sum: 3
  
  ///存储模板函数
  std::function<double(double, double)> fun_sum2 = Sumfun2<double>;
  std::cout<<"sum2: "<<fun_sum2(1.1,2.9)<<std::endl;  ///sum2: 4
  
 ///存储函数对象
  std::function<void(int)> fun_printnum = PrintNum();
  fun_printnum(50);  ///PrintNum: 50
  
 ///存储lambda
  std::function<void(double)> fun_lambda = [](double num)->void{std::cout<<"fun_lambda: "<<num<<std::endl;};
  fun_lambda(60.7);  ///fun_lambda: 60.7
  
  ////存储到数据成员访问器的调用
  std::function<int(Foo const&)> fun_foo_num = &Foo::num_;
  std::cout<<"Foo num: "<<fun_foo_num(10)<<std::endl; ///Foo num: 10
  
  ///存储到成员函数的调用
  std::function<void(const Foo&, int)> fun_foo = &Foo::Print_add;
  Foo foo(7);
  fun_foo(foo, 4); ///Foo Print_add: 11
  fun_foo(8,7);  ///Foo Print_add: 15
  
  ////// std::function与std::bind结合使用
  ///  std::bind绑定普通函数
  std::function<int()> fun_bind = std::bind(Sumfun, 3, 6); ///绑定输入第一个参数为3,第二个参数为6
  std::cout<<"sum3: "<<fun_bind()<<std::endl;
  
  ///存储到类成员函数及对象的调用
  ///std::placeholders::_1为占位符,表示将来传递给fun_bind_foo1的参数
  std::function<void(int)> fun_bind_foo1 = std::bind(&Foo::Print_add, foo,std::placeholders::_1);  ///foo 按值传递
  std::function<void(int)> fun_bind_foo2 = std::bind(&Foo::Print_add, &foo,std::placeholders::_1);  ///foo 按指针传递
  foo.num_ = 6;
  fun_bind_foo1(5); ///Foo Print_add: 12  (5 + 7)
  fun_bind_foo2(5); ///Foo Print_add: 11  (5 +6)
  
  //// 函数参数的重新排序
  int n = 7;
  auto fun2 = std::bind(fun1, std::placeholders::_2,  std::placeholders::_1,
                        std::placeholders::_1,  std::cref(n),  n);
  n = 20;
  fun2(1, 2,33333); ///2 1 1 20 7 
  /// std::placeholders::_2 表示传入参数中的第二个参数, std::placeholders::_1表示传入参数中的第一个参数
  /// 传入的第三个参数 33333未被使用
  ///第4个参数按引用传递,第5个参数按值传递
  
  /// 嵌套 bind 子表达式共享占位符
  auto f2 = std::bind(fun1, std::placeholders::_3, std::bind(g, std::placeholders::_2),
                      std::placeholders::_1, 4, 5);
  f2(10, 11, 12); /// 12 11 10 4 5
  /// 进行到 fun1(12, g(11), 10, 4, 5);  的调用
  printf("fun1 add: %p\n",fun1);      ///fun1 add: 0x402ee0
  printf("f2   add: %p\n",f2);        ///f2   add: 0x7ffcc5b9e890  这两个函数具有不同的内存地址
  
  ///常见使用情况:以分布绑定 RNG
  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';  ///0 1 8 5 5 2 0 7 7 10 生成[0~10]的随机序列
  return 0;
 }

参考

https://zh.cppreference.com/w/cpp/utility/functional/function
https://zh.cppreference.com/w/cpp/utility/functional/bind

猜你喜欢

转载自blog.csdn.net/Sandy_WYM_/article/details/82850193
今日推荐