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
作为函数调用名,param1
和param2
为函数参数。在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解析