C++-function包装器的应用

embedded/2024/11/30 12:12:11/

 

目录

 1.什么是 std::function?

2. function 包装器的原型

 3.使用 function 封装不同类型的函数对象

代码分析

 4.实际应用:

 5. bind 绑定:修改参数传递顺序和数量

2.1 使用 bind 绑定修改参数传递顺序

2.2. bind 绑定:指定特定参数

2.3. bind 绑定与类成员函数

总结:😊



😊前言:在现代 C++ 中,std::function 是一个非常有用的工具,它使得函数能够像对象一样传递、存储和调用。随着 C++11 的到来,std::function 被引入到标准库中,成为函数式编程和回调机制的核心组件之一。在这篇博客中,我们将深入探讨 std::function 的工作原理、应用场景及其优缺点。

 1.什么是 std::function

std::function 是 C++11 引入的一个模板类,用于封装任何可调用对象如普通函数、Lambda 表达式、函数指针、成员函数指针或函数对象等)。它允许你存储一个可调用对象,并在需要时调用它。这使得我们可以更加灵活地编写代码,特别是在需要传递回调函数或异步任务时,std::function 显得尤为重要。

std::function 是通过类型擦除实现的,它可以在运行时动态地将不同类型的可调用对象转化为统一的接口。简单来说,它允许你用一个通用的对象来代替不同类型的函数或函数指针

2. function 包装器的原型

std::function在头文件<functional>

// 类模板原型如下template <class T> function; // undefinedtemplate <class Ret, class... Args>class function<Ret(Args...)>;

模板参数说明:

Ret: 被调用函数的返回类型Args…:被调用函数的形参。

 3.使用 function 封装不同类型的函数对象

#include <iostream>
#include <functional>
#include <string>using namespace std;// 普通函数
void func(int n)
{cout << "普通函数: " << n << endl;
}// 仿函数
struct Func
{void operator()(int n){cout << "仿函数: " << n << endl;}
};// Lambda 表达式
auto lambda = [](int n) { cout << "Lambda 表达式: " << n << endl; };int main()
{// 使用 std::function 封装不同类型的函数function<void(int)> f;f = func;           // 包装普通函数f(10);f = Func();         // 包装仿函数f(20);f = lambda;         // 包装 Lambda 表达式f(30);return 0;
}
代码分析

我们定义了三个不同类型的函数:一个普通函数 func一个仿函数 Func一个 Lambda 表达式 lambda

然后,使用 std::function<void(int)> 来封装这三种不同类型的函数对象。

通过调用包装后的 f,我们可以统一的方式执行这些不同的函数对象。(适配器)

这种方式使得我们能够将多种类型的可调用对象统一为一个接口,方便管理和使用。


 4.实际应用:

 150. 逆波兰表达式求值 - 力扣(LeetCode)

 解法一:

class Solution {
public:int evalRPN(vector<string>& tokens) {stack<int> st;for(auto& to:tokens){if(to=="+"||to=="-"||to=="*"||to=="/"){int right=st.top();st.pop();int left=st.top();st.pop();switch(to[0]){case '+':st.push(left+right);break;case '-':st.push(left-right);break;case '*':st.push(left*right);break;case '/':st.push(left/right);break;}}else{st.push(stoi(to));}}return st.top();}
};

解法二: 利用function包装器:

class Solution 
{
public:int evalRPN(vector<string>& tokens) {// 解题思路:操作数入栈,遇到操作符,取两个数计算后,入栈// 建立映射关系unordered_map<string, function<int(int, int)>> hash = {{"+", [](int x, int y)->int { return x + y; } },{"-", [](int x, int y)->int { return x - y; } },{"*", [](int x, int y)->int { return x * y; } },{"/", [](int x, int y)->int { return x / y; } },};stack<int> s;for(auto str : tokens){if(str != "+" && str != "-" && str != "*" && str != "/")s.push(stoi(str));else{// 注意:先获取 y,再获取 xint y = s.top();s.pop();int x = s.top();s.pop();s.push(hash[str](x, y));}}return s.top();}
};

function作为C++11的一个知识,还是非常好用的。😊

 5. bind 绑定:修改参数传递顺序和数量

bind 是 C++ 标准库中的一个函数模板,它允许我们对函数参数进行预先绑定或重新排列,从而生成一个新的可调用对象。bind 的强大之处在于,它不仅能够指定某些参数的固定值,还能改变参数传递的顺序,极大地提高了灵活性。

函数原型:

template <class Fn, class... Args>
bind (Fn&& fn, Args&&... args);

 fn 是传递的 函数对象args 是传给函数的 可变参数包,这里使用了 万能引用(引用折叠),使其在进行模板类型推导时,既能引用左值,也能引用右值。

2.1 使用 bind 绑定修改参数传递顺序
#include <iostream>
#include <functional>using namespace std;void Func(int a, int b)
{cout << "Func: " << a << " " << b << endl;
}int main()
{// 正常调用Func(10, 20);// 使用 bind 改变参数顺序auto RFunc = bind(Func, std::placeholders::_2, std::placeholders::_1);RFunc(10, 20);  // 输出: Func: 20 10return 0;
}

代码分析

bind(Func, std::placeholders::_2, std::placeholders::_1) 通过 placeholders::_1placeholders::_2 指定了新的参数顺序,即将原本的第二个参数和第一个参数交换。

当我们调用 RFunc(10, 20) 时,实际上是将 20 作为第一个参数,10 作为第二个参数传递给 Func

这种参数顺序的改变,在一些特定的应用场景下非常有用,特别是在函数签名不一致时,可以方便地进行适配。

2.2. bind 绑定:指定特定参数

bind 还可以用于指定函数的某些参数为固定值,从而减少后续调用时需要传递的参数个数。

示例代码:使用 bind 绑定指定特定参数

#include <iostream>
#include <functional>using namespace std;void Func(int a, int b)
{cout << "Func: " << a << " " << b << endl;
}int main()
{// 使用 bind 绑定第一个参数auto RFunc = bind(Func, 100, std::placeholders::_1);RFunc(20);  // 输出: Func: 100 20return 0;
}

代码分析

我们通过 bind(Func, 100, std::placeholders::_1) 将第一个参数绑定为固定值 100

后续调用时,我们只需要传递第二个参数 20bind 会自动将 100 作为第一个参数传递给 Func

2.3. bind 绑定与类成员函数

bind 还可以用于绑定类成员函数。对于普通函数,绑定非常简单,但对于成员函数,我们需要额外注意如何传递类的对象或指针。

示例代码:使用 bind 绑定静态成员函数

#include <iostream>
#include <functional>using namespace std;class Test
{
public:static void funcA(int val){cout << "静态成员函数 funcA: " << val << endl;}
};int main()
{// 使用 bind 绑定静态成员函数auto RFunc = bind(&Test::funcA, std::placeholders::_1);RFunc(10);  // 输出: 静态成员函数 funcA: 10return 0;
}

代码分析

对于静态成员函数,我们可以直接使用 &Test::funcA 来绑定。

bind 会自动处理函数的绑定,并返回一个新的可调用对象 RFunc我们可以使用它来调用函数。

 示例代码:使用 bind 绑定非静态成员函数

#include <iostream>
#include <functional>using namespace std;class Test
{
public:Test(int n) : _n(n) {}void funcB(int val){cout << "非静态成员函数 funcB: " << val * _n << endl;}private:int _n;
};int main()
{Test t(10);// 使用 bind 绑定非静态成员函数auto RFunc = bind(&Test::funcB, t, std::placeholders::_1);RFunc(5);  // 输出: 非静态成员函数 funcB: 50return 0;
}

 代码分析

对于非静态成员函数,我们需要提供类的对象 t 作为参数来绑定。

bind 会将 t&Test::funcB 结合,并生成一个新的可调用对象。

总结:😊

通过 std::functionbind,C++ 提供了强大的函数包装和绑定功能,使得我们能够在不同类型的函数之间进行无缝切换、修改参数传递顺序以及绑定特定参数。这些工具极大地增强了代码的灵活性和可重用性,特别是在需要对多个不同函数进行统一管理时,它们提供了非常便捷的解决方案。在实际开发中,这些技巧不仅能帮助我们提升编程效率,还能让代码更加简洁和优雅。


http://www.ppmy.cn/embedded/141740.html

相关文章

vue面试题+答案扩展(70道)

在当前前端领域&#xff0c;熟练使用Vue.js是非常重要的技能要求之一。针对Vue.js进行充分的面试准备&#xff0c;可以帮助求职者在众多应聘者中脱颖而出。本文准备了100道vue的面试题&#xff0c;点击链接后可以查看详细的原理&#xff0c;优势劣势、使用场景、代码示例等。 注…

Jenkins 忘记登录密码

Jenkins 是一个流行的持续集成和持续部署工具&#xff0c;广泛应用于软件开发和测试领域。但经常性会遇到忘记登录密码的情况&#xff0c;下面将介绍解决 Jenkins 忘记登录密码的方法。 通过配置文件修改密码 找到 Jenkins 的安装目录&#xff0c;对于 war 安装版&#xff0c;…

455 分发饼干

这是一道入门级的贪心算法题&#xff0c;这道题的关键有两点&#xff1a; 1.首先需要对孩子的胃口大小&#xff0c;饼干大小进行排序 2.小尺寸的饼干用来满足小胃口的孩子&#xff0c;大尺寸的饼干用来满足大胃口的孩子&#xff0c;用这样的策略分发饼干。 如果用大尺寸的饼干去…

【计算机视觉算法与应用】模板匹配、图像配准

目录 1. 基于灰度值的模板匹配 2. 基于相关性的模板匹配 3. 基于形状的模板匹配 4. 基于组件的模板识别 5. 基于形变的模板匹配 6. 基于描述符的模板匹配 7. 基于点的模板匹配 性能比较 模板匹配的算法实现需要结合具体需求和应用场景来选择方法。以下是基于 OpenCV 的…

helm部署golang服务

Helm 是 Kubernetes 的一个包管理工具,类似于 Linux 中的 apt 或 yum。它使得在 Kubernetes 上部署和管理应用程序变得更加简单和高效。 安装 https://get.helm.sh/helm-v3.16.3-linux-amd64.tar.gz具体版本号可以在github上看到最新的版本号,然后替换上面链接来获取。gith…

python打包深度学习虚拟环境

今天师兄让我把环境打包发给他&#xff0c;我才知道可以直接打包深度学习虚拟环境&#xff0c;这样另一个人就不用辛辛苦苦的去装环境了&#xff0c;我们都知道有些论文他需要的环境很难装上。比如装Apex&#xff0c;装 DCN&#xff0c;mmcv-full 我现在把3090机子上的ppft虚拟…

github webhooks 实现网站自动更新

本文目录 Github Webhooks 介绍Webhooks 工作原理配置与验证应用云服务器通过 Webhook 自动部署网站实现复制私钥编写 webhook 接口Github 仓库配置 webhook以服务的形式运行 app.py Github Webhooks 介绍 Webhooks是GitHub提供的一种通知方式&#xff0c;当GitHub上发生特定事…

uniapp在App端定义全局弹窗,当打开关闭弹窗会触发onShow、onHide生命周期怎么解决?

在uniapp(App端)中实现自定义弹框&#xff0c;可以通过创建一个透明页面来实现。点击进入当前页面时&#xff0c;页面背景会变透明&#xff0c;用户可以根据自己的需求进行自定义&#xff0c;最终效果类似于弹框。 遇到问题&#xff1a;当打开弹窗(进入弹窗页面)就会触发当前页…