包装器
- function包装器
- function的介绍
- function的使用
- function的使用场景
- function的意义
 
- bind包装器
- bind的介绍
- bind的使用
 
function包装器
function的介绍
function是用来包装函数的,所以叫做包装器或者适配器,fuction的本质其实是一个类模板。
 function的类模板如下:
template <class T> function;     // undefined
template <class Ret, class... Args>
class function<Ret(Args...)>;
参数说明:
- Ret:被包装的可调用对象的返回值类型。
- Args…:被包装的可调用对象的形参类型。
function的使用
在使用function的时候,需要包含头文件#include< functional >
 function可以对一下五种函数进行包装:
- 函数指针
int add(int a, int b)
{
	return a + b;
}
int main()
{
	std::function<int(int, int)> func1 = add;//传递函数指针
	std::cout << func1(1, 1) << std::endl;
	return 0;
}
- 仿函数(函数对象)
struct plus
{
	int operator()(int a,int b)
	{
		return a + b;
	}
};
int main()
{
	std::function<int(int, int)> func2 = plus();//传递仿函数(函数对象)
	std::cout << func2(3, 4) << std::endl;
	return 0;
}
需要注意的是,传递的是一个函数对象,因为仿函数operator()是创建在对象中的
- lambda表达式
int main()
{
	std::function<int(int, int)> func3 = [](int a, int b)->int {return a + b; };
	//传递lambda函数
	std::cout << func3(5, 6) << std::endl;
	return 0;
}
- 静态成员函数
class Func
{
public:
	static int addi(int a,int b)
	{
		return a + b;
	}
	double addd(double a,double b)
	{
		return a  + b;
	}
};
int main()
{
	std::function<int(int, int)> func4 = &Func::addi;//传递静态类成员函数,可以省略&
	std::cout << func4(5, 6) << std::endl;
	return 0;
}
- 传递非静态成员函数
class Func
{
public:
	static int addi(int a,int b)
	{
		return a + b;
	}
	double addd(double a,double b)
	{
		return a  + b;
	}
};
int main()
{
	std::function<int(Func,double, double)> func5 = &Func::addd;//传递非静态成员函数,不可以省略&
	std::cout << func5(Func(), 5.5, 6.6) << std::endl;
	return 0;
}
需要注意的,在传递非静态成员函数的时候,&是不可以省略的,而且还要多传递一个成员变量this指针,所以可以就传递一个临时变量Func()。
function的使用场景
统一类型的使用场景:
 函数模板会根据不同的模板参数,实例化出等同于不同模板参数函数的实例,假设有一个函数模板:
 第一个模板参数是可以任意调用的函数指针,仿函数,lambda表达式;
 第二个模板参数是任意的自定义类型或内置类型。
template<class T,class F>
T useF(F f,T a)
{
	static int num = 0;
	cout << "num的值: " << ++num << endl;
	cout << "num的地址: " << &num << endl;
	return f(a);
}
int add(int a)
{
	return 1 + a;
}
struct Func 
{
	int operator()(int a)
	{
		return 1 + a;
	}
};
int main()
{
	cout << useF(add,1) << endl;
	cout << useF(Func(),1) << endl;
	cout << useF([](int a)->int {return 1 + a; }, 1) << endl;
	return 0;
}

 这样实例化出来了三份不同的函数实例,造成这样的现象是因为第一个模板参数。
 现在有解决方法就是吧,函数指针和仿函数以及lambda全部都用function包装起来,然后再传给useF那么就只会实例化出来一份函数实例。
 
function的意义
- 将可调用对象的类型进行统一,便于对其进行统一化管理。
- 包装后明确了可调用对象的返回值和形参类型,更加方便使用者使用。
bind包装器
bind的介绍
bind也是可以包装函数的一种方法,bind可以包装一个可调用的对象(函数),然后生成一个新的可调用对象(函数)去适配原来这个可调用对象(函数)的参数bind的本质是一个函数模板。
template <class Fn, class... Args>
/* unspecified */ bind(Fn&& fn, Args&&... args);
template <class Ret, class Fn, class... Args>
/* unspecified */ bind(Fn&& fn, Args&&... args);
参数说明:
- Fn:可调用的对象
- Args:参数列表,占位符
bind的使用
调用bind的一般形式为:auto newCallable = bind(callable, arg_list);
- callable:需要包装的可调用对象。
- newCallable:生成的新的可调用对象。
- arg_list:逗号分隔的参数列表,对应给定的callable的参数。当调用newCallable时,newCallable会调用callable,并传给它arg_list中的参数。
int sub(int a, int b)
{
	return a - b;
}
int main()
{
	auto newsub = bind(sub,placeholders::_1,placeholders::_2);
	cout << newsub(2,1) << endl;
}
auto可以用function来代替,function<()()> newCallable = bind(callable, arg_list);
int sub(int a, int b)
{
	return a - b;
}
int main()
{
	function<int(int, int)> newsub = bind(sub, placeholders::_1, placeholders::_2);
	cout << newsub(2, 1) << endl;
}
其中的placeholsers::_1和placeholders::_2,对应的就是sub的第一个参数和第二个参数。
 bind传递参数的顺序
 
 placeholders_n,是按照顺序绑定可调用对象的参数的是不会改变的。
 bind包装类成员函数:
class func
{
public:
	int sub(int a, int b)
	{
		return a - b;
	}
};
int main()
{
	function<int(int, int)> newsub = bind(&func::sub,func(),placeholders::_1,placeholders::_2);
	cout << newsub(2,1)  << endl;
	return 0;
}
需要注意:类成员函数的又this指针,所以需要在传递可调用对象这个参数之后,再传递一个临时变量给this指针。



















