当前位置: 首页 > ai >正文

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();
    }
    };

http://www.xdnf.cn/news/10476.html

相关文章:

  • 自然图像数据集
  • Lesson 26 The best art critics
  • 软考-数据库系统工程师-程序设计语言知识要点
  • 如何安装ojdbc6-12.1.0.1与je-5.0.58的mvn构建依赖jar包?
  • 问题 D: 学 DP 导致的
  • Camera相机人脸识别系列专题分析之十:人脸特征检测FFD算法之低功耗libvega_face.so人脸识别检测流程详解
  • 超标量处理器设计6-指令解码
  • SPA-RL:通过Stepwise Progress Attribution训练LLM智能体
  • 第十一讲 | 多态
  • ∑ 1/n 调和级数 是 发散的
  • 解决 Win11 睡眠后黑屏无法唤醒的问题
  • C语言 — 文件
  • 初学者如何微调大模型?从0到1详解
  • 串口通信技术及USART应用研究
  • IDEA PyCharm 等工具如何同时打开多个窗口
  • Redis笔记
  • 英一真题阅读单词笔记 06年
  • 系统性学习C语言-第十三讲-深入理解指针(3)
  • 使用langchain实现五种分块策略:语义分块、父文档分块、递归分块、特殊格式、固定长度分块
  • 计算机网络技术
  • 【PostgreSQL 05】PostgreSQL扩展开发实战:从自定义函数到插件开发的完整指南
  • C# 类和继承(构造函数的执行)
  • 数据结构测试模拟题(3)
  • 【STM32开发板】接口部分
  • 象棋里的卧槽马、侧面虎、金钩马的方位与解析
  • 13.三种低功耗和RTC实时时钟
  • CppCon 2014 学习: C++ on Mars
  • Go中MAP底层原理分析
  • Python打卡第42天
  • 建筑兔零基础python自学记录102|Beautiful Soup库(1)-15