function
- 1 function包装器使用场景
- 2 包装器
- 3 包装成员函数
- 4 一道例题
- 5 包装器的意义
1 function包装器使用场景
现在有代码如下:
要求声明出这两个函数的类型
int f(int a,int b)
{
return a + b;
}
struct Functor
{
int operator(int a,int b)
{
return a + b;
}
}
可以这样声明
int f(int a,int b)
{
return a + b;
}
struct Functor
{
int operator()(int a,int b)
{
return a + b;
}
};
int main()
{
int (*pf1)(int,int) = f;
Functor f2;
return 0;
}
但是这两个声明的类型完全是不一样的,一个函数指针,一个是类。
现在要求声明的类型完全一样,就可以使用C++11中的包装器。
#include <iostream>
#include <functional>
using namespace std;
int f(int a,int b)
{
return a + b;
}
struct Functor
{
int operator()(int a,int b)
{
return a + b;
}
};
int main()
{
function<int(int,int)> f1 = f;
function<int(int,int)> f2 = Functor();
cout << f1(1,1) << endl;//2
cout << f2(2,2) << endl;//4
return 0;
}
包装以后,这两个对象的类型是一样的。
下面正式介绍包装器。
2 包装器
function包装器 也叫作适配器。C++中的function本质是一个类模板,也是一个包装器。对可调用对象进行再封装适配。
std::function在头文件
// 类模板原型如下
template <class T> function; // undefined
template <class Ret, class... Args>
class function<Ret(Args...)>;
模板参数说明:
Ret: 被调用函数的返回类型
Args…:被调用函数的形参
C++11中可调用对象有函数指针,仿函数,lambda表达式(本质还是仿函数),这些都可以用包装器进行包装。
int f(int a,int b)
{
return a + b;
}
struct Functor
{
int operator()(int a,int b)
{
return a + b;
}
};
int main()
{
function<int(int,int)> f1 = f;
function<int(int,int)> f2 = Functor();
function<int(int,int)> f3 = [](int a,int b){return a + b;};
cout << f1(1,1) << endl;//2
cout << f2(2,2) << endl;//4
cout << f3(3,3) << endl;//6
return 0;
}
3 包装成员函数
成员函数分为静态成员函数和非静态成员函数。
class Plus
{
public:
Plus(int rate = 2) : _rate(rate)
{}
static int plusi(int a, int b)
{
return a + b;
}
double plusd(double a, double b)
{
return (a + b) * _rate;
}
private:
int _rate;
};
静态成员函数的包装:
需要加个作用域
function<int(int, int)> f1 = Plus::plusi;
非静态成员的包装:
C++11规定,非静态成员的包装除了加域名外,还要加上&符号。
非静态成员函数的参数是默认带this指针的,所以包装器参数列表里要加上类名。
function<int(Plus,int, int)> f2 = &Plus::plusd;
int main()
{
function<int(int,int)> f1 = Plus::plusi;
function<int(Plus,int, int)> f2 = &Plus::plusd;
cout << f1(1, 1) << endl;//2
cout << f2(Plus(3),1, 1) << endl;//6,匿名对象方式使用
Plus p(3);
cout << f2(p, 1, 1) << endl;//6,创建了一个对象再去调用
return 0;
}
4 一道例题
这是力扣上一道逆波兰表达式的题,可以尝试用map结合包装器写一下。
150.逆波兰表达式求值
求解逆波兰表达式的步骤如下:
定义一个栈,依次遍历所给字符串。 如果遍历到的字符串是数字则直接入栈。
如果遍历到的字符串是加减乘除运算符,则从栈定抛出两个数字进行对应的运算,并将运算后得到的结果压入栈中。
所给字符串遍历完毕后,栈顶的数字就是逆波兰表达式的计算结果。
这是一般的写法:
class Solution {
public:
int evalRPN(vector<string>& tokens) {
stack<int> s;
for(auto& i : tokens)
{
if(i == "+" || i == "-" || i == "*" || i == "/")
{
int right = s.top();
s.pop();
int left = s.top();
s.pop();
switch(i[0])
{
case '+' :
s.push(right + left);
break;
case '-' :
s.push(left - right);
break;
case '*' :
s.push(right * left);
break;
case '/' :
s.push(left / right);
break;
}
}
else
{
s.push(stoi(i));
}
}
return s.top();
}
};
结合包装器和map写法:
class Solution {
public:
int evalRPN(vector<string>& tokens) {
stack<int> s;
map<string,function<int(int,int)>> op =
{
{"+",[](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& i : tokens)
{
if(op.count(i))
{
int right = s.top();
s.pop();
int left = s.top();
s.pop();
s.push(op[i](left,right));
}
else
{
s.push(stoi(i));//字符转整数
}
}
return s.top();
}
};
5 包装器的意义
将可调用对象的类型进行统一,便于对其进行统一化管理。
包装后明确了可调用对象的返回值和形参类型,更加方便使用者使用