宝安网站建设-信科网络,北京网站建设公司制作网站,做家居的网站,网页设计入门书阅读导航 引言一、function包装器1. 概念2. 基本使用3. 逆波兰表达式求值#xff08;1#xff09;普通写法#xff08;2#xff09;使用包装器以后的写法 二、bind() 函数温馨提示 引言
很高兴再次与大家分享关于 C11 的一些知识。在上一篇文章中#xff0c;我们讲解了 c… 阅读导航 引言一、function包装器1. 概念2. 基本使用3. 逆波兰表达式求值1普通写法2使用包装器以后的写法 二、bind() 函数温馨提示 引言
很高兴再次与大家分享关于 C11 的一些知识。在上一篇文章中我们讲解了 condition_variable 的使用方法。今天我们将继续探讨 C11 中的两个重要概念function 包装器和 bind() 函数。这两个概念在 C11 中具有非常重要的作用它们可以帮助我们更好地管理函数指针和函数对象并且可以大大提高代码的可读性和可维护性。在接下来的这篇文章中我们将深入探讨这两个概念的使用方法和注意事项。
一、function包装器
1. 概念
当我们在C中使用函数指针或函数对象时经常会遇到一些灵活性和可复用性的问题。C11引入了一个强大的工具——function包装器它可以解决这些问题。
function包装器是一个通用的函数封装器可以容纳各种可调用对象如函数指针、函数对象、成员函数指针等并提供统一的接口来调用这些可调用对象。通过使用function包装器我们可以将不同类型的可调用对象存储在一个容器中方便统一管理和调用。
2. 基本使用
function包装器的使用非常简单。首先我们需要包含头文件functional。然后我们可以使用std::function模板类来定义一个function对象。例如
#include functionalstd::functionint(int) func;上述代码定义了一个名为func的function对象它可以接受一个int类型的参数并返回一个int类型的值。我们可以将各种可调用对象赋值给func例如函数指针、函数对象、lambda表达式等。例如
int myFunction(int x) {return x * 2;
}struct MyFunctor {int operator()(int x) {return x 3;}
};func myFunction; // 函数指针
int result1 func(2); // 调用myFunction结果为4MyFunctor functor;
func functor; // 函数对象
int result2 func(2); // 调用functor结果为5func [](int x) { return x * x; }; // lambda表达式
int result3 func(2); // 调用lambda表达式结果为4通过使用function包装器我们可以将不同类型的可调用对象统一存储并调用极大地提高了代码的灵活性和可复用性。此外function还提供了其他功能如判空、交换等。
需要注意的是function包装器的使用可能会引入一些性能开销因为它需要进行动态分派。在性能要求较高的场景中可以考虑使用函数指针或模板来代替function包装器。
3. 逆波兰表达式求值
接下来我们来讲一道题相信通过这个OJ题目可以让大家更加了解function包装器。首先我先简单介绍一下这个题目逆波兰表示法Reverse Polish Notation, RPN是一种数学表达式的书写方式它通过将操作符放在两个操作数之后来表示一个算术表达式从而避免了使用括号。
题目链接 1普通写法 如果当前元素是操作符‘’、‘-’、‘*’ 或 ‘/’ 从栈中弹出两个操作数分别记为 num2 和 num1。根据当前操作符进行计算并将结果压入栈中。 如果当前元素是操作数整数 将其转换为整数并压入栈中。 遍历结束后栈中只会剩下一个元素即为最终的计算结果。
class Solution {
public:int evalRPN(vectorstring tokens) {stacklong long st; // 创建一个存储操作数的栈使用 long long 类型以避免溢出问题for(auto str : tokens) // 遍历表达式中的每个元素{if(str || str - || str * || str /) // 当前元素为操作符{long long right st.top(); // 取出栈顶的操作数作为右操作数st.pop(); // 弹出栈顶元素long long left st.top(); // 取出新的栈顶元素作为左操作数st.pop(); // 弹出栈顶元素// 根据操作符进行计算并将结果压入栈中switch(str[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(stoll(str)); // 将字符串转换为 long long 类型并压入栈中}}return st.top(); // 返回栈顶元素即最终的计算结果}
};
2使用包装器以后的写法
class Solution {
public:int evalRPN(vectorstring tokens) {stackint st; // 创建一个存储操作数的栈mapstring, functionint(int, int) opFuncMap // 创建一个从操作符到对应计算函数的映射表{{ , [](int i, int j){return i j; } }, // lambda 函数实现加法计算{ -, [](int i, int j){return i - j; } }, // lambda 函数实现减法计算{ *, [](int i, int j){return i * j; } }, // lambda 函数实现乘法计算{ /, [](int i, int j){return i / j; } } // lambda 函数实现除法计算};for(auto str : tokens) // 遍历表达式中的每个元素{if(opFuncMap.find(str) ! opFuncMap.end()) // 当前元素为操作符{int right st.top(); // 取出栈顶的操作数作为右操作数st.pop(); // 弹出栈顶元素int left st.top(); // 取出新的栈顶元素作为左操作数st.pop(); // 弹出栈顶元素// 根据操作符进行计算并将结果压入栈中st.push(opFuncMap[str](left, right));}else // 当前元素为操作数{st.push(stoi(str)); // 将字符串转换为整数并压入栈中}}return st.top(); // 返回栈顶元素即最终的计算结果}
};
二、bind() 函数
std::bind函数定义在头文件中是一个函数模板它就像一个函数包装器(适配器)接受一个可调用对象callable object生成一个新的可调用对象来“适应”原对象的参数列表。一般而言我们用它可以把一个原本接收N个参数的函数fn通过绑定一些参数返回一个接收M个M可以大于N但这么做没什么意义参数的新函数。同时使用std::bind函数还可以实现参数顺序调整等操作。 头文件 bind() 函数位于 functional 头文件中因此在使用该函数之前需要包含该头文件。 函数原型 bind() 函数的原型如下所示 template class Fn, class... Args
bind(Fn fn, Args... args);参数解释 Fn表示函数类型或函数对象类型。Args表示参数类型。fn要进行绑定的函数或函数对象。args要绑定的参数。 返回值 bind() 函数返回一个新的可调用对象该对象可以像原始函数一样被调用但会自动传递已绑定的参数给 fn。 使用示例 下面是一个使用 bind() 函数的示例代码
#include functional
#include iostream
using namespace std;// 定义一个普通函数 Plus接收两个 int 类型参数返回它们的和
int Plus(int a, int b)
{return a b;
}// 定义一个类 Sub包含一个成员函数 sub接收两个 int 类型参数返回它们的差
class Sub
{
public:int sub(int a, int b){return a - b;}
};int main()
{// 绑定全局函数 Plus 到一个 std::function 对象 func1 上并使用 placeholders 占位符表示待绑定的参数。// 将第一个和第二个参数分别绑定到调用 func1 时传递的第一个和第二个参数上。std::functionint(int, int) func1 std::bind(Plus, placeholders::_1, placeholders::_2);// 使用 auto 定义变量 func2将全局函数 Plus 绑定到它上面并将第一个参数和第二个参数分别指定为 1 和 2。// 因为 Plus 函数已经被绑定这里不需要再使用 placeholders 占位符了。auto func2 std::bind(Plus, 1, 2);// 创建一个 Sub 对象 s将它的成员函数 sub 绑定到 std::function 对象 func3 上。// 使用 placeholders 占位符表示待绑定的参数。将第一个和第二个参数分别绑定到调用 func3 时传递的第一个和第二个参数上。Sub s;std::functionint(int, int) func3 std::bind(Sub::sub, s, placeholders::_1, placeholders::_2);// 创建另一个 std::function 对象 func4将它绑定到 s 的成员函数 sub 上。// 使用 placeholders 占位符表示待绑定的参数。这里将第一个参数和第二个参数分别绑定到调用 func4 时传递的第二个和第一个参数上。std::functionint(int, int) func4 std::bind(Sub::sub, s, placeholders::_2, placeholders::_1);// 分别输出各个函数对象的返回值cout func1(1, 2) endl; // 输出 3即 Plus(1, 2) 的结果cout func2() endl; // 输出 3即 Plus(1, 2) 的结果cout func3(1, 2) endl; // 输出 -1即 s.sub(1, 2) 的结果cout func4(1, 2) endl; // 输出 1即 s.sub(2, 1) 的结果return 0;
}这段代码演示了如何使用 std::bind 函数将函数对象和成员函数绑定到 std::function 对象上并使用占位符 std::placeholders::_1 和 std::placeholders::_2 来表示待绑定的参数。
我们定义了一个普通的函数 Plus它接收两个 int 类型的参数并返回它们的和。我们定义了一个类 Sub其中包含一个成员函数 sub它接收两个 int 类型的参数并返回它们的差。 在 main 函数中我们首先用 std::bind 将全局函数 Plus 绑定到 std::function 对象 func1 上使用占位符 std::placeholders::_1 和 std::placeholders::_2 分别表示第一个和第二个参数。这样我们可以使用 func1 来调用 Plus 函数并传递实际的参数。 我们使用 auto 关键字定义了一个变量 func2将全局函数 Plus 绑定到它上面并指定第一个参数为 1第二个参数为 2。因为在这种情况下不需要使用占位符所以我们直接指定了参数的值。我们创建了一个 Sub 类的对象 s并将其成员函数 sub 绑定到 std::function 对象 func3 上使用占位符 std::placeholders::_1 和 std::placeholders::_2 分别表示第一个和第二个参数。这样我们可以通过 func3 调用 s.sub 函数并传递实际的参数。我们创建了另一个 std::function 对象 func4将其绑定到 s 的成员函数 sub 上并使用占位符 std::placeholders::_2 和 std::placeholders::_1 分别表示第一个和第二个参数。这样我们可以通过 func4 调用 s.sub 函数并以不同的顺序传递实际的参数。
温馨提示
感谢您对博主文章的关注与支持另外我计划在未来的更新中持续探讨与本文相关的内容会为您带来更多关于C以及编程技术问题的深入解析、应用案例和趣味玩法等。请继续关注博主的更新不要错过任何精彩内容
再次感谢您的支持和关注。期待与您建立更紧密的互动共同探索C、算法和编程的奥秘。祝您生活愉快排便顺畅