C++11新特性包装器
目录
1.function
2。 150. 逆波兰表达式求值
编辑
1.function
C++11中提供了新的类模板function,它是一个包装器,可以包装其它可以存储调用其它的可调用对象,这里的可调用对象包括函数指针,仿函数,.lambda,bind表达式等,存储的可调用对象被称为function目标,若function不含目标,则城它为空,会抛出异常。
function的链接被包含在头文件<functional>中,我们在cpp中包含这个文件可以去使用function了。
函数指针,仿函数,lambda等可调用对象的类型各不相同,function的优势就是统一类型,对它们都进行包装,这样在很多地方就可以方便使用可调用对象。
我们可以看到下面的例子,function说实话,它就是一个包装器,它把add函数包装成()形式去调用,但实际调用的还是原函数的地址,我们打印出两次调用add的地址发现它们相同,所以得出结论,function包装了add来进行()的统一调用,对于lambda,仿函数亦是如此。
#include<iostream>
using namespace std;
#include<functional>
int add(int a, int b)
{cout << add<<endl;return a + b;
}
int main()
{int a = add(1, 2);function<int(int, int)>f = add;int b=f(1, 2);return 0;
}
在文件中我们可以看到function实际上用了一个参数包和特化来实现。R是返回类型,参数包里是传参类型。下面我们再写一下仿函数,lambda的function包装怎么写。
这里其实我们function等号右边其实要写函数地址,只是普通函数函数名会自动取地址我们不用手动写,但是类中定义的普通成员函数需要写,这里C++对于类中的成员函数提供了两种方式,一种是传对象,一种是传对象地址,因为类中的普通成员函数第一个隐藏参数是this指针,方便知道是哪个对象调用了它,所以我们得给出对象或者对象地址。
至于lambda是这样写的function<int(int, int)> f3 = [](int a, int b) {return a + b; };
类的成员函数我们分别写了对象和对象地址两种,c++对于这两种写法都是支持的,对象通过.*去回调成员函数,对象地址通过->去回调成员函数,所以支持了这两种写法。本质function它就是一个包装器,它对原函数没有改变,调用的函数还是原函数,只是包装成()统一调用了。
#include<functional>
int f(int a, int b)
{
return a + b;
}
struct Functor
{
public:
int operator() (int a, int b)
{
return a + b;
}
};
class Plus
{
public:
Plus(int n = 10)
:_n(n)
{}
static int plusi(int a, int b)
{
return a + b;
}
double plusd(double a, double b)
{
return (a + b) * _n;
}
private:
int _n;
};
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;
cout << f2(1, 1) << endl;
cout << f3(1, 1) << endl;
// 包装静态成员函数
// 成员函数要指定类域并且前⾯加&才能获取地址
function<int(int, int)> f4 = &Plus::plusi;
cout << f4(1, 1) << endl;
// 包装普通成员函数
// 普通成员函数还有⼀个隐含的this指针参数,所以绑定时传对象或者对象的指针过去都可以
function<double(Plus*, double, double)> f5 = &Plus::plusd;
Plus pd;
cout << f5(&pd, 1.1, 1.1) << endl;
function<double(Plus, double, double)> f6 = &Plus::plusd;
cout << f6(pd, 1.1, 1.1) << endl;
cout << f6(pd, 1.1, 1.1) << endl;
function<double(Plus&&, double, double)> f7 = &Plus::plusd;
cout << f7(move(pd), 1.1, 1.1) << endl;
cout << f7(Plus(), 1.1, 1.1) << endl;
return 0;
}
这里我们如果传对象调用实际上去通过.*去回调成员函数了,编译器明白是哪个对象来调这个成员函数。我们给对象地址编译器也可以通过->去调用成员函数,所以这两种方法都是通过回调成员函数去调的。
obj.*
用于 对象实例 调用成员指针。-
obj->*
用于 对象指针 调用成员指针。 - 成员指针(函数/变量)在 动态绑定、回调、泛型编程 中很有用。
-
#include <iostream> using namespace std;class Student { public:string name;int age;Student(string n, int a) : name(n), age(a) {} };int main() {Student s("Alice", 20);Student* sPtr = &s;// 定义成员变量指针string Student::*namePtr = &Student::name;int Student::*agePtr = &Student::age;// 使用 obj.*cout << "Name: " << s.*namePtr << ", Age: " << s.*agePtr << endl;// 使用 obj->*cout << "Name: " << sPtr->*namePtr << ", Age: " << sPtr->*agePtr << endl;return 0; }
2150. 逆波兰表达式求值
-
- 我们传统做法是用栈来做,遇到数字入栈,遇到运算符出栈运算。得到最后结果。代码如下:
class Solution { public:int evalRPN(vector<string>& tokens) {stack<int>nums;auto it = tokens.begin();while (it != tokens.end()){if (*it == "+"){int tmp = nums.top();nums.pop();int tmp1 = nums.top();nums.pop();nums.push(tmp + tmp1);}else if (*it == "-"){int tmp = nums.top();nums.pop();int tmp1 = nums.top();nums.pop();nums.push(tmp1 - tmp);}else if (*it == "*"){int tmp = nums.top();nums.pop();int tmp1 = nums.top();nums.pop();nums.push(tmp1 * tmp);}else if (*it == "/"){int tmp = nums.top();nums.pop();int tmp1 = nums.top();nums.pop();nums.push(tmp1 / tmp);}else {nums.push(stoi(*it));}it++;}return nums.top();} };
学了function和lambda之后我们可以简化代码,利用map的映射来解决问题:
-
class Solution { public: int evalRPN(vector<string>& tokens) { stack<int> st; // function作为map的映射可调⽤对象的类型 map<string, function<int(int, int)>> opFuncMap = { {"+", [](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;}} }; for(auto& str : tokens) { if(opFuncMap.count(str)) // 操作符 { int right = st.top(); st.pop(); int left = st.top(); st.pop(); int ret = opFuncMap[str](left, right); st.push(ret); } else { st.push(stoi(str)); } } return st.top(); } };