深入解析:【C++:C++11收尾】解构C++可调用对象:从入门到精通,掌握function包装器与bind适配器包装器详解


在这里插入图片描述

个人主页艾莉丝努力练剑

专栏传送门:《C语言》《数据结构与算法》《C/C++干货分享&学习过程记录
Linux操作系统编程详解》《笔试/面试常见算法:从基础到进阶》《Python干货分享

⭐️为天地立心,为生民立命,为往圣继绝学,为万世开太平

艾莉丝的简介:

在这里插入图片描述


艾莉丝的C++专栏简介:

在这里插入图片描述



C++学习阶段的三个参考文档

看库文件(非官方文档):Cplusplus.com

在这里插入图片描述

这个文档在C++98、C++11时候还行,之后就完全没法用了……

准官方文档(同步更新)——还 可以看语法C++准官方参考文档

在这里插入图片描述
这个行,包括C++26都同步了,我们以后主要会看这个。

官方文档(类似论坛):Standard C++

在这里插入图片描述
这个网站上面会有很多大佬,类似于论坛。


在这里插入图片描述


8 ~> 包装器

8.1 function

8.1.1 结构

template <class T>
  class function; // undefined
  template <class Ret, class... Args>
    class function<Ret(Args...)>;

8.1.2 概念

std::function 是一个类模板,也是一个包装器 std::function 的实例对象可以包装存储其他的可以调用对象,包括函数指针、仿函数、lambdabind表达式 等,存储的可调用对象被称为 std::function 的目标。若std::function不含目标,则称它为空。调用空 std::function 的目标导致抛出std::bad_function_call异常。

在这里插入图片描述

以上是function的原型,他被定义头文件中。std::function是function的官方文件链接。

在这里插入图片描述

函数指针、仿函数、 lambda 等可调用对象的类型各不相同, std::function 的优势就是统一类型,对他们都可以进行包装,这样在很多地方就方便声明可调用对象的类型,下面的第二个代码样例展示了 std::function 作为map的参数,实现字符串和可调用对象的映射表功能。

8.1.3 function实现

在这里插入图片描述
在这里插入图片描述

8.1.4 重写逆波兰表达式求值

力扣题目链接:150. 逆波兰表达式求值

力扣题解链接:后缀法 && 操作符紧跟操作数 && switch…case…语句解决

这道题我们已经写过一次了,这次我们会采用另一种方式实现。

题目描述:

在这里插入图片描述
对应博客链接:【C++STL :stack && queue (一) 】STL:stack与queue全解析|深入使用(附高频算法题详解)

在这里插入图片描述

传统方式实现(之前的实现)——

class Solution {
public:
int evalRPN(vector<string>& tokens) {
  stack<int> st;
    for(auto& str : tokens)
    {
    // 判断四种运算符
    if(str == "+" || str == "-" || str == "*" || str == "/")
    {
    // 运算符
    int right = st.top();
    st.pop();
    int left = st.top();
    st.pop();
    switch(str[0]) // 大坑:switch...case语句只能是int类型
    {
    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(str)); // 字符串转整型,to_string
    }
    }
    return st.top();
    }
    };

我们可以现学现用,使用map映射string和function的方式实现一下——

在这里插入图片描述
这种方式的最大优势之一是方便扩展,假设还有其他运算,我们增加map中的映射即可,算法实现如下所示——

class Solution{
public:
int evalRPN(vector<string>& tokens) {
  map<string,function<int(int,int)>> opFuncMap =
    {
    {"+",[](int a,int b) {return a + b;}},
    {"-",[](int a,int b) {return a - b;}},
    {"*",[](int a,int b) {return a * b;}},
    {"/",[](int a,int b) {return a / b;}}
    };
    stack<int> st;
      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();
      }
      };

8.2 bind

8.2.1 结构

simple(1)
template <class Fn, class... Args>
  /* unspecified */ bind (Fn&& fn, Args&&... args);
  with return type (2)
  template <class Ret, class Fn, class... Args>
    /* unspecified */ bind (Fn&& fn, Args&&... args);

8.2.2 概念

bind 是一个函数模板,它也是一个可调用对象的包装器,可以把他看做一个函数适配器,对接收的fn可调用对象进行处理后返回一个可调用对象。 bind 可以用来调整参数个数和参数顺序。 bind 也在这个头文件中。

调用bind的一般形式:

auto newCallable =bind(callable,arg_list)

其中newCallable本身是一个可调用对象,arg_list是一个逗号分隔的参数列表,对应给定的callable的参数。当我们调用newCallable时,newCallable会调用callable,并传给它arg_list中的参数。

arg_list中的参数可能包含形如_n的名字,其中n是一个整数,这些参数是占位符,表示newCallable的参数,它们占据了传递给newCallable的参数的位置。数值n表示生成的可调用对象中参数的位置:_1为newCallable的第一个参数,_2为第二个参数,以此类推。_1 / _2 / _3…这些占位符放到placeholders的一个命名空间中。

在这里插入图片描述

8.2.3 代码实现

在这里插入图片描述


9 ~> 智能指针预告

C++专栏的主线内容马上就要结束啦,艾莉丝将把智能指针作为C++干货专栏的主线(C++98、C++11部分)的终章,之后本专栏还会更新,内容以C++11、C++14、C++17、C++20、以及其它的加餐内容为主了。感谢大家对艾莉丝的支持!希望uu们能够继续支持艾莉丝哦!感谢大佬们的支持!


C++11完整代码示例与实践演示

Test.cpp:

#define  _CRT_SECURE_NO_WARNINGS  1
#include<iostream>
  #include<vector>
    #include<functional>
      using namespace std;
      // ===================C++11:包装器=================
      //--------------------function---------------------
      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;
            //
            //	vector<function<int(int, int)>> v;
              //	v.push_back(f);
              //	v.push_back(Functor());
              //	v.push_back([](int a, int b) {return a + b; });
              //
              //	for (auto& f : v)
              //	{
              //		cout << f(1, 1) << endl;
              //	}
              //	cout << endl;
              //
              //	//function<int(int, int)> f4 = Plus::plusi;
                //	function<int(int, int)> f4 = &Plus::plusi;
                  //	cout << f4(1, 1) << endl;
                  //
                  //	function<double(Plus*, double, double)> f5 = &Plus::plusd;
                    //	Plus ps;
                    //	cout << f5(&ps, 1.1, 1.1) << endl;
                    //
                    //	function<double(Plus, double, double)> f6 = &Plus::plusd;
                      //	cout << f6(ps, 1.1, 1.1) << endl;
                      //
                      //	function<double(Plus, double, double)> f7 = &Plus::plusd;
                        //	cout << f7(Plus(), 1.1, 1.1) << endl;		// Plus():匿名对象
                        //
                        //	function<double(Plus&&, double, double)> f8 = &Plus::plusd;
                        //	cout << f8(Plus(), 1.1, 1.1) << endl;
                        //
                        //	auto pf1 = &Plus::plusd;
                        //	Plus* ptr = &ps;
                        //	cout << (ps.*pf1)(1.1, 1.1) << endl;
                        //	cout << (ptr->*pf1)(1.1, 1.1) << endl;	// 无法显式传this指针
                          //
                          //	return 0;
                          //}
                          // 运行结果:
                          // 2
                          // 2
                          // 2
                          // 2
                          // 2
                          // 2
                          // 
                          // 2
                          // 22
                          // 22
                          // 22
                          // 22
                          // 22
                          // 22
                          // ------------------bind-------------------
                          // _n占位
                          using placeholders::_1;
                          using placeholders::_2;
                          using placeholders::_3;
                          int Sub(int a, int b)
                          {
                          return (a - b) * 10;
                          }
                          int SubX(int a, int b, int c)
                          {
                          return(a - b - c) * 10;
                          }
                          int main()
                          {
                          // bind的本质是返回一个仿函数对象
                          // 调整参数顺序(这个功能不常用)
                          // _1代表第一个实参
                          // _2代表第二个实参
                          // ...
                          // 交换
                          auto f1 = bind(Sub, _1, _2);
                          auto f2 = bind(Sub, _2, _1);
                          // _1代表第一个实参
                          // _2代表第二个实参
                          cout << f1(10, 5) << endl;
                          cout << f2(10, 5) << endl;
                          // 调整参数个数
                          auto f3 = bind(SubX, 10, _1, _2);
                          cout << f3(15, 5) << endl;
                          // _1代表第一个实参
                          // _2代表第二个实参
                          // 底层operator(),调用SubX,第一个参数10, 15, 5
                          auto f4 = bind(SubX, _1, 10, _2);
                          cout << f4(15, 5) << endl;
                          // 底层operator(),调用SubX,第一个参数15, 10, 5
                          auto f5 = bind(SubX, _1, _2, 10);
                          cout << f5(15, 5) << endl;
                          // 底层operator(),调用SubX,第一个参数15, 5, 10
                          function<double(Plus, double, double)> f7 = &Plus::plusd;
                            cout << f7(Plus(), 1.1, 1.1) << endl;
                            cout << f7(Plus(), 2.2, 1.1) << endl;
                            cout << f7(Plus(), 3.3, 1.1) << endl;
                            function<double(Plus&&, double, double)> f8 = &Plus::plusd;
                            cout << f8(Plus(), 1.1, 1.1) << endl;
                            cout << f8(Plus(), 2.2, 1.1) << endl;
                            cout << f8(Plus(), 3.3, 1.1) << endl << endl;
                            // 计算复利(利息)的lambda
                            auto func1 = [](double rate, double money, int year)->double {
                            double ret = money;
                            for (int i = 0; i < year; i++)
                            {
                            ret += ret * rate;
                            }
                            return ret - money;
                            };
                            // 年利率1.5%
                            function<double(double)> func_r1_5_3y = bind(func1, 0.015, _1, 3);
                              function<double(double)> func_r1_5_5y = bind(func1, 0.015, _1, 5);
                                function<double(double)> func_r1_5_20y = bind(func1, 0.015, _1, 20);
                                  // 本金100000元
                                  cout << func_r1_5_3y(100000) << endl;
                                  cout << func_r1_5_5y(100000) << endl;
                                  cout << func_r1_5_20y(100000) << endl;
                                  // 这只股票如果利率有10%呢
                                  function<double(double)> func_r10_3y = bind(func1, 0.1, _1, 3);
                                    function<double(double)> func_r10_5y = bind(func1, 0.1, _1, 5);
                                      function<double(double)> func_r10_20y = bind(func1, 0.1, _1, 20);
                                        cout << func_r10_3y(100000) << endl;
                                        cout << func_r10_5y(100000) << endl;
                                        cout << func_r10_20y(100000) << endl;
                                        // 如果你的10万元到了“股神”巴菲特手里------19%,同样的时间会怎么样?
                                        function<double(double)> func_r19_3y = bind(func1, 0.19, _1, 3);
                                          function<double(double)> func_r19_5y = bind(func1, 0.19, _1, 5);
                                            function<double(double)> func_r19_20y = bind(func1, 0.19, _1, 20);
                                              cout << func_r19_3y(100000) << endl;
                                              cout << func_r19_5y(100000) << endl;
                                              cout << func_r19_20y(100000) << endl;
                                              return 0;
                                              }
                                              // 运行结果:
                                              // 50
                                              // -50
                                              // -100
                                              // 0
                                              // 0
                                              // 22
                                              // 33
                                              // 44
                                              // 22
                                              // 33
                                              // 44
                                              // 
                                              // 4567.84
                                              // 7728.4
                                              // 34685.5
                                              // 33100
                                              // 61051
                                              // 572750
                                              // 68515.9
                                              // 138635
                                              // 3.14294e+06

结尾

uu们,本文的内容到这里就全部结束了,艾莉丝再次感谢您的阅读!

结语:希望对学习C++相关内容的uu有所帮助,不要忘记给博主“一键四连”哦!

往期回顾

【C++:C++11】C++11新特性深度解析:从可变参数模板到Lambda表达式

博主在这里放了一只小狗,大家看完了摸摸小狗放松一下吧!
૮₍ ˶ ˊ ᴥ ˋ˶₎ა

在这里插入图片描述

posted @ 2025-12-27 12:19  yangykaifa  阅读(3)  评论(0)    收藏  举报