1.function包装器
1.1 概念介绍
ret = func(x);
函数包装器,也称为函数适配器或函数封装器,是一种编程模式,用于将函数或对象包装在另一层抽象中,以改变其调用签名或行为。C++中的function本质是一个类模板,也是一个包装器。其包含在头文件<functional>。function可以把这些所有参数类型和返回值类型相同的可调用类型(函数指针,仿函数对象,lamber表达式对象),统一的管理起来,让它们都变成一个类型。
1.2 语法使用
function类原型:
#include<iostream>
#include <functional>
using namespace std;
int f(int a, int b)
{
return a + b;
}
struct Functor
{
public:
int operator() (int a, int b)
{
return a + b;
}
};
int main()
{
// 函数名(函数指针)
function<int(int, int)> func1 = f;
cout << func1(1, 2) << endl;
// 函数对象
function<int(int, int)> func2 = Functor();
cout << func2(1, 2) << endl;
// lamber表达式
function<int(int, int)> func3 = [](int a,int b)
{return a + b; };
cout << func3(1, 2) << endl;
return 0;
}
在上述代码中,f
函数,Functor
仿函数,以及lambda
表达式,它们的返回值都是int
,参数类型也是int,int
,因此可以经过包装器包装为function<int(int,int)>而变为同一类型,
这样就可以统一管理了。
1.3 function包装类的成员函数
class Plus
{
public:
static int plusi(int a, int b)
{
return a + b;
}
double plusd(double a, double b)
{
return a + b;
}
};
int main()
{
//类的成员函数
function<int(int, int)> func4 = &Plus::plusi;
cout << func4(1, 2) << endl;
//用法一
function<double(Plus, double, double)> func5 = &Plus::plusd;
cout << func5(Plus(), 1.1, 2.2) << endl;
//用法二
function<double(Plus*, double, double)> func6 = &Plus::plusd;
Plus tmp;
cout << func6(&tmp, 1.1, 2.2) << endl;
return 0;
}
在使用function包装类的成员函数时需要注意,类的非静态成员函数参数中天然包含了一个该类指针参数,即this指针。所以我们包装时需要在function参数列表中也加上该类指针或者该类,实例化时也同理。
1.4 实例应用
int evalRPN(vector<string>& tokens) {
map<string, function<int(int, int)>> opfunc = {
{"+",[](int x,int y) { return x + y; }},
{"-",[](int x,int y) { return x - y; }},
{"*",[](int x,int y) { return x * y; }},
{"/",[](int x,int y) { return x / y; }},
};
stack<int> q;
for (auto& e : tokens)
{
if (e == "+" || e == "-" || e == "*" || e == "/")
{
int num1 = q.top();
q.pop();
int num2 = q.top();
q.pop();
q.push(opfunc[e](num2, num1));
}
else
{
q.push(stoi(e));
}
}
return q.top();
}
2.bind包装器
2.1 概念介绍
std::bind
是C++11中引入的一个函数适配器,它允许您绑定函数或函数对象的一部分参数,从而创建一个新的可调用实体。std::bind
的定义位于<functional>
头文件中。它的基本用途是将一个函数与其参数一起进行绑定,生成一个新的函数对象,这个新对象可以在不同的上下文中被调用,而不需要再次提供那些已经绑定的参数。
2.2 语法使用
第一个参数为可调用对象,后续参数为该可调用对象的参数。其后续参数的语法比较特别,C++11后新增一个命名空间域placeholders
,其内部会存储很多变量,这些变量用于函数的传参,变量的名字为_x,
表示第x
个参数。例如_1可调用对象的第一个参数,_2为第二个参数。
使用如下:
using namespace placeholders;
int Plus(int a, int b)
{
return a + b;
}
class Sub
{
public:
int sub(int a, int b)
{
return a - b;
}
};
int main()
{
//表示绑定函数plus 参数分别由调用 func1 的第一,二个参数指定,将placeholders空间
//展开后即可直接使用_x.
function<int(int, int)> func1 = bind(Plus, placeholders::_1,_2);
//func2的类型为 function<int(int, int)> 与func1类型一样
//表示绑定函数 plus 的第一,二为: 10, 20,即可不用传参
auto func2 = bind(Plus, 10, 20);
// 参数调换顺序
auto Div = [](int a, int b) { return a / b; };
auto func3 = bind(Div, _2, _1);
cout << func1(1, 2) << endl;
cout << func2() << endl;
cout << func3(20, 60);
return 0;
}
一般而言,我们用bind函数可以把一个原本接收N个参数的函数fn,通过绑定一些参数,返回一个接收M个(M 可以大于N,但这么做没什么意义)参数的新函数。同时,使用bind函数还可以实现参数顺序调整等操作。
2.3 function包装类的成员函数
class Sub
{
public:
int sub(int a, int b)
{
return a - b;
}
};
int main()
{
Sub s;
function<int(int, int)> func4 = bind(&Sub::sub, s, _1, _2);
cout << func4(1, 2) << endl;
return 0;
}
在使用bind包装类的成员函数时需要注意,类的非静态成员函数参数中天然包含了一个该类指针参数,即this指针。所以我们包装时需要在bind参数列表中也加上该类指针或者该类,实例化时也同理。