C++11新特性包装器

 目录

1.function

2。  150. 逆波兰表达式求值

​编辑


1.function

C++11中提供了新的类模板function,它是一个包装器,可以包装其它可以存储调用其它的可调用对象,这里的可调用对象包括函数指针,仿函数,.lambda,bind表达式等,存储的可调用对象被称为function目标,若function不含目标,则城它为空,会抛出异常。

function的链接被包含在头文件中,我们在cpp中包含这个文件可以去使用function了。

函数指针,仿函数,lambda等可调用对象的类型各不相同,function的优势就是统一类型,对它们都进行包装,这样在很多地方就可以方便使用可调用对象。

我们可以看到下面的例子,function说实话,它就是一个包装器,它把add函数包装成()形式去调用,但实际调用的还是原函数的地址,我们打印出两次调用add的地址发现它们相同,所以得出结论,function包装了add来进行()的统一调用,对于lambda,仿函数亦是如此。

#include
using namespace std;
#include
int add(int a, int b)
{
	cout << add<f = add;
	int b=f(1, 2);
	return 0;
}

C++11新特性包装器_第1张图片

在文件中我们可以看到function实际上用了一个参数包和特化来实现。R是返回类型,参数包里是传参类型。下面我们再写一下仿函数,lambda的function包装怎么写。

C++11新特性包装器_第2张图片

这里其实我们function等号右边其实要写函数地址,只是普通函数函数名会自动取地址我们不用手动写,但是类中定义的普通成员函数需要写,这里C++对于类中的成员函数提供了两种方式,一种是传对象,一种是传对象地址,因为类中的普通成员函数第一个隐藏参数是this指针,方便知道是哪个对象调用了它,所以我们得给出对象或者对象地址。

至于lambda是这样写的function f3 = [](int a, int b) {return a + b; };

类的成员函数我们分别写了对象和对象地址两种,c++对于这两种写法都是支持的,对象通过.*去回调成员函数,对象地址通过->去回调成员函数,所以支持了这两种写法。本质function它就是一个包装器,它对原函数没有改变,调用的函数还是原函数,只是包装成()统一调用了。

#include
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 f1 = f;
function f2 = Functor();
function f3 = [](int a, int b) {return a + b; };
cout << f1(1, 1) << endl;
cout << f2(1, 1) << endl;
cout << f3(1, 1) << endl;
// 包装静态成员函数
// 成员函数要指定类域并且前⾯加&才能获取地址
function f4 = &Plus::plusi;
cout << f4(1, 1) << endl;
// 包装普通成员函数
// 普通成员函数还有⼀个隐含的this指针参数,所以绑定时传对象或者对象的指针过去都可以
function f5 = &Plus::plusd;
Plus pd;
cout << f5(&pd, 1.1, 1.1) << endl;
function f6 = &Plus::plusd;
cout << f6(pd, 1.1, 1.1) << endl;
cout << f6(pd, 1.1, 1.1) << endl;
function 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 
    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. 逆波兰表达式求值

  • C++11新特性包装器_第3张图片

  • 我们传统做法是用栈来做,遇到数字入栈,遇到运算符出栈运算。得到最后结果。代码如下:
    class Solution {
    public:
        int evalRPN(vector& tokens) {
             stacknums;
     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& tokens) {
    stack st;
    // function作为map的映射可调⽤对象的类型
    map> 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();
    }
    };

你可能感兴趣的:(C++,c++,java,开发语言)