一. 为什么要有包装器?
function 包装器,也叫作适配器。C++ 中的 function 本质上是一个类模板,也是一个包装器。接下来我们来看看,C++ 为什么引入 function 呢?
在 C++ 中,可调用对象有以下三种:函数名/函数指针、仿函数对象、lambda 表达式
// 加法普通函数
int NormalPlus(int num1, int num2)
{
return num1 + num2;
}
// 加法仿函数
class FunctorPlus
{
public:
int operator()(int num1, int num2)
{
return num1 + num2;
}
};
int main()
{
// 加法 lambda 表达式
auto LambdaPlus = [](int num1, int num2) {
return num1 + num2; };
// 1、调用普通函数
NormalPlus(10, 20);
// 2、调用仿函数对象
FunctorPlus obj;
obj(10, 20);
// 3、调用 lambda 表达式
LambdaPlus(10, 20);
}
可以看到,它们的调用方式可以不能说相似,只能说是一模一样,且它们函数体中执行的内容都是完全相同的;但是它们彼此之间的类型不同,不能进行相互赋值等操作。
上面是三种不同的可调用对象,那么它们的类型不同还可以理解;但是在 lambda 表达式中,就算功能相似的 lambda 表达式,它们直接的类型也互不相同:
这就导致在很多应用场景中,lambda 表达式使用起来是非常不便的。比如之前我们大量进行回调函数时,会采用函数指针的方式,构建一个函数指针数组,调用时按其对应的下标调用即可。但是 lambda 表达式则不然,每一个 lambda 表达式的类型不相同,我们没办法去开辟一个定类型的数组,也就意味着传统的函数指针的方式是不可行的。
包装器的诞生就是为了解决这个问题,通过包装器,可以让功能相似的可调用对象(函数名/函数指针、仿函数对象和 lambda 表达式)的类型统一,使其可以相互联系,相互转化。
二. 什么是包装器?
包装器是个类模板,它的定义在头文件 functional 中
下面看看具体的示例:
也就是说,在 function 的模板列表中,第一个参数是返回值的类型,随后在括号里依次传入形参的类型;而后在赋值的时候,只需要让其等于已经定义过的可调用对象,这样就算包装完成了,最后我们可以使用这个包装好的对象来代替之前的可调用对象,去执行它们的功能。
三. 包装器的使用
还是刚刚的例子,我们分别包函数名/函数指针,仿函数对象,lambda 表达式,看看包装完之后它们各自的类型是什么
// 加法普通函数
int NormalPlus(int num1, int num2)
{
return num1 + num2;
}