C++11 std::bind函数,std::function函数

Posted Jqivin

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C++11 std::bind函数,std::function函数相关的知识,希望对你有一定的参考价值。


一、std::bind函数

1.简单介绍

std::bind函数定义在头文件functional中,是一个函数模板,它就像一个函数适配器,接受一个可调用对象(callable object),生成一个新的可调用对象来“适应”原对象的参数列表。std::bind将可调用对象与其参数一起进行绑定,绑定后的结果可以使用std::function保存. std::bind主要有以下作用:

将可调用对象和其参数绑定成一个仿函数;
只绑定部分参数,减少可调用对象传入的参数。即将多元(参数个数为n,n>1)可调用对象转换成一元或者(n-1)元的可调用对象

与function可调用对象包装器一块使用可以绑定类的成员函数。

使用形式:

auto newcallable = bind(fun,arg_list);

当调用newCallable时,会去调用callable,并传给它arg_list中的参数。

需要注意的是:arg_list中的参数可能包含占位符,形如_n的名字。其中n是一个整数,这些占位符表示newCallable的参数,它们占据了传递给newCallable的参数的位置。数值n表示生成的可调用对象中参数的位置:_1为newCallable的第一个参数,_2为第二个参数,以此类推。

我们使用auto newCallable来保存bind的返回值,是因为我们不关心它的真正的返回类型(实际上std::bind的返回类型是一个stl内部定义的仿函数类型),只需要直到他是一个仿函数,可以直接赋值给一个std::function

2、使用

(1)预绑定的参数是以值传递的形式,不预绑定的参数要用std::placeholders(占位符)的形式占位,从_1开始,依次递增,是以引用传递的形式(当fun函数参数以引用的时候);即默认情况下,bind的那些不是占位符的参数被拷贝到bind返回的可调用对象中。当需要把对象传到bind中的参数中时,需要使用ref或者cref。
std::placeholders表示新的可调用对象的第几个参数,而且与原函数的该占位符所在位置的进行匹配。

在这里插入图片描述

(2)bind绑定类成员函数时,第一个参数表示对象的成员函数的指针,第二个参数表示对象的地址(如果不是对象的地址,传入的是对象的副本),这是因为对象的成员函数需要有this指针。并且编译器不会将对象的成员函数隐式转换成函数指针,需要通过&手动转换;
在这里插入图片描述
(3)std::bind的返回值是可调用实体,可以直接赋给std::function
在这里插入图片描述

二、可调用对象

什么是可调用对象?

一组执行任务的语句都可以视为一个函数,一个可调用对象
在程序设计中,我们习惯把那些具有复用性的一组语句抽象为函数,把变化的部分抽象为函数的参数。函数的使用极大地减少代码重复性。在C++中,具有函数这种行为的方式有很多,比如下面这个

func(paran1,param2);

这里的func作为函数调用名,param1param2为函数参数。在C++中就func的类型,可能有下面几种类型:

  • 普通函数
  • 类成员函数
  • 类静态函数
  • 仿函数(函数对象)
  • 函数指针
  • lambda表达式
  • std::function

普通函数,类成员函数,类静态函数的调用不再介绍。

仿函数

使用类来模拟函数的调用行为,重载一个类的operator()方法,即可像调用一个函数一样调用类。

#include<iostream>
using namespace std;
class Add
{
public:
	int operator()(int a, int b)
	{
		return a + b;
	}
};
int main()
{
	Add add;
	int res = add(10, 20);  //像一个函数一样
	//add.operator()(10, 20);等价
	cout << res << endl;
	return 0;
}

执行结果
在这里插入图片描述

函数指针

指向函数的指针。是一个指针。可以将函数名赋值给相同类型的函数指针,可以通过调用函数指针调用函数。
函数指针是标准的C/C++的回调函数的使用解决方案函数类型由它的返回值和参数类型决定,与函数名无关

bool fun(int a,int b)

上述函数类型是:bool(int,int)
上述函数的函数指针pf是:bool (*pf)(int,int)
函数名即为函数指针
定义函数指针的方法:

typedef bool (*fun)(int,int)  //定义一个fun类型的函数指针

示例:

int fun(int a, int b)
{
	cout << "this is fun" << endl;
	return a + b;
}
typedef int(*fp)(int, int);  //fp是一个函数指针类型,相当于int *类型
int fun1(fp f, int a, int b)
{
	cout << "this is fun1" << endl;
	return f(a, b);
}
//等价于下面的
int fun2(int(*f)(int, int), int a, int b)
{
	cout << "this is fun2" << endl;
	return f(a, b);
}
int main()
{
	cout << fun1(fun,10, 20) << endl;
	cout << fun2(fun, 10, 20) << endl;
	return 0;
}

执行结果:

this is fun1
this is fun
30
this is fun2
this is fun
30

lambda表达式

三、std::function 可调用对象包装器

1.定义

由上文可以看出:由于可调用对象的定义方式比较多,但是函数的调用方式较为类似,因此需要使用一个统一的方式保存可调用对象或者传递可调用对象。于是,std::function就诞生了。

std::function是一个可调用对象包装器,是一个类模板,可以容纳除了类成员函数指针之外的所有可调用对象,它可以用统一的方式处理函数、函数对象、函数指针,并允许保存和延迟它们的执行

2.注意点

(1)需要引用functional
(2)需要注意对于类成员函数,因为类成员函数包含this指针参数,所以单独使用std::function是不够的,还需要结合使用std::bind函数绑定this指针以及参数列表。
(3)std::function可以取代函数指针的作用,因为它可以延迟函数的执行,特别适合作为回调函数使用。它比普通函数指针更加的灵活和便利。
(4)std::function对C++中各种可调用实体(普通函数、Lambda表达式、函数指针、以及其它函数对象等)的封装,形成一个新的可调用的std::function对象,简化调用;

3.使用

#include<functional>
std::function<函数类型>
//例如std::function<bool(int,int)>

(1)基本用法

代码展示

//普通函数
int add(int a, int b)
{
	return a + b;
}
typedef int(*Fp_Type)(int, int);
class Object
{
public:
	int Oadd(int a, int b) { return a + b; }
	static int OSadd(int a, int b) { return a + b; }
	int operator()(int a, int b) { return a + b; }
};
typedef std::function<int(int, int)> func;
int main()
{
	Object obj;
	//std::function<int(int, int)> func = add; 
	//普通函数
	func f1 = add;
	cout << f1(10, 20) << endl;

	//函数指针
	Fp_Type fp = add;
	func f2 = fp;
	cout << f2(10, 20) << endl;

	//类成员函数
	func f3 = std::bind(&Object::Oadd,obj, placeholders::_1, placeholders::_2);
	cout << f3(10, 20) << endl;

	//类静态函数
	func f4 = Object::OSadd;
	cout << f4(10, 20) << endl;

	//仿函数
	func f5 = obj;
	cout << f5(100, 200) << endl;

	return 0;	
}

运行结果
在这里插入图片描述
示例:

void add1(int& a, int b)
{
	cout << "add:   a = " << a << "  b = " << b << endl;
	a++;
	b++;
}
int main()
{
	int a = 10, b = 20;
	std::function<void(int&, int)> fun = add1;
	fun(a, b);
	cout << "main:  a = " << a << "  b = " << b << endl;
	fun(a, b);
	cout << "main:  a = " << a << "  b = " << b << endl;
	
	std::function<void(int&, int)> fun2 = bind(fun, placeholders::_1, placeholders::_2);
	fun2(a,b);
	cout << "main:  a = " << a << "  b = " << b << endl;
	fun2(a,b);
	cout << "main:  a = " << a << "  b = " << b << endl;

	return 0;

}

结果:

add:   a = 10  b = 20
main:  a = 11  b = 20
add:   a = 11  b = 20
main:  a = 12  b = 20
add:   a = 12  b = 20
main:  a = 13  b = 20
add:   a = 13  b = 20
main:  a = 14  b = 20
请按任意键继续. . .

(2)作为回调函数和参数使用

class A
{
private:
	std::function<void()> call_back;
public:
	A(const std::function<void()> &f):call_back(f){}
	A(){}
	void notify()
	{
		call_back(); //回调到上层
	}
};
class Foo
{
public:
	void operator()()
	{
		cout << "hello jqw" << endl;
	}
};
int main()
{
	Foo foo;
	//std::function<void()> f = foo;
	A a(foo);
	a.notify();
	return 0;
}

执行结果:

hello jqw

四、关于回调函数

回调就是通过把函数等作为另外一个函数的参数的形式,在调用者层指定被调用者行为的方式。

通过上面的介绍,我们知道,可以使用函数指针,以及std::function作为函数参数类型,从而实现回调函数.
在这里插入图片描述

参考:http://uusama.com/735.html

以上是关于C++11 std::bind函数,std::function函数的主要内容,如果未能解决你的问题,请参考以下文章

C++11 std::bind std::function 变参函数

C++11 std::bind std::function 变参函数

C++11新特性应用--实现延时求值(std::function和std::bind)

C++11 std::bind和std::function解析

C++11之用std::function和std::bind实现观察者模式

C++ STL应用与实现22: 函数组合之1:如何使用std::bind (since C++11)