包装器
包装器是一个类模板
C 中的可调用对象:函数指针(类型定义很复杂)、仿函数对象(定义一个类的时候,用的时候有些麻烦,其次不适合统一类型)、lambda(没有类型概念)、包装器
function包装器
function
包装器 也叫作适配器。C 中的function
本质是一个类模板,也是一个包装器。
std::function
在头文件<functional>
类模板原型:
template <class T> function; // undefined
template <class Ret, class... Args>
class function<Ret(Args...)>;
模板参数说明:
Ret
: 被调用函数的返回类型
Args…
:被调用函数的形参
他不是用来定义可调用对象,是用来包装可调用对象:
代码语言:javascript复制#include<functional>
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)> fc1;
//包装函数指针
function<int(int, int)> fc2 = f;
cout << fc2(1, 2) << endl;
//包装仿函数
function<int(int, int)> fc3 = Functor();
cout << fc3(2, 3) << endl;
//包装lambda表达式
function<int(int, int)> fc4 = [](int x, int y) {return x y; };
cout << fc4(3, 4) << endl;
return 0;
}
应用场景
力扣:150.逆波兰表达式求值
代码语言:javascript复制class Solution {
public:
int evalRPN(vector<string>& tokens) {
stack<int> st;
//命令和对应的函数动作结合
map<string,function<int(int,int)>> opfuncMap={
{" ",[](int a,int b){return a b;}},
{"-",[](int a,int b){return a-b;}},
{"*",[](int a,int b){return a*b;}},
{"/",[](int a,int b){return a/b;}}
};
for(auto& str:tokens)
{
if(opfuncMap.count(str)) // 是操作符
{
function<int(int,int)> func=opfuncMap[str];
int right=st.top();
st.pop();
int left=st.top();
st.pop();
st.push(func(left,right));
}
else //是操作数
{
st.push(stoi(str));
}
}
return st.top();
}
};
包装成员函数指针
在包装静态成员指针函数时,当我们需要用到某个函数时,需要在前面指定类域。但如果不是静态时,不仅需要添加类域,还需要添加一个&
。
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)> fc1 = Plus::plusi;
cout << fc1(1, 2) << endl;
function<double(Plus*, double, double)> fc2 = &Plus::plusd;
Plus plus;
cout << fc2(&plus, 1.1, 2.2) << endl;
function<double(Plus, double, double)> fc3 = &Plus::plusd;
//Plus plus;
cout << fc3(Plus(), 1.1, 2.2) << endl;
return 0;
}
fc1
是一个 std::function<int(int, int)>
对象,绑定到静态成员函数 Plus::plusi
。调用 fc1(1, 2)
输出 3
。
fc2
是一个 std::function<double(Plus*, double, double)>
对象,绑定到非静态成员函数 Plus::plusd
。它接受一个 Plus*
指针和两个 double
类型的参数。调用 fc2(&plus, 1.1, 2.2)
计算 1.1 2.2
并输出 3.3
。
bind
std::bind
函数定义在头文件中,是一个函数模板,它就像一个函数包装器(适配器),接受一个可调用对象(callable objec
t),生成一个新的可调用对象来“适应”原对象的参数列表。一般而言,我们用它可以把一个原本接收N
个参数的函数fn
,通过绑定一些参数,返回一个接收M
个(M
可以大于N
,但这么做没什么意义)参数的新函数。同时,使用std::bind
函数还可以实现参数顺序调整等操作。
原型:
代码语言:javascript复制template <class Fn, class... Args>
bind (Fn&& fn, Args&&... args);
with return type (2)
template <class Ret, class Fn, class... Args>
bind (Fn&& fn, Args&&... args);
可以将bind
函数看作是一个通用的函数适配器,它接受一个可调用对象,生成一个新的可调用对象来“适应”原对象的参数列表。
调用bind
的一般形式:auto newCallable = bind(callable,arg_list);
调整参数顺序
代码语言:javascript复制int Sub(int a, int b)
{
return a - b;
}
int main()
{
auto f1 = Sub;
cout << f1(10, 5) << endl;
auto f2 = bind(Sub, placeholders::_2, placeholders::_1);
cout << f2(10, 5) << endl;
return 0;
}
调整参数个数
代码语言:javascript复制class Sub
{
public:
int sub(int a, int b)
{
return a - b;
}
};
int main()
{
Sub sub;
auto f3 = bind(&Sub::sub, Sub(), placeholders::_2, placeholders::_1);
cout << f3(10, 5) << endl;
return 0;
}
参数顺序:bind(&Sub::sub, &s, _2, _1)
绑定了成员函数 sub
和 s
对象,并指定 _2
和 _1
的位置。调用 f3(10, 5)
会将 5
映射到 _2
,10
映射到 _1
,因此 f3(10, 5)
实际上会调用 s.sub(5, 10)
,结果是 5 - 10
,即 -5
。