• C++拾遗--lambda表达式原理


    参考网址: https://blog.csdn.net/zhangxiangdavaid/article/details/44064765

    C++拾遗--lambda表达式原理

    前言
    lambda表达式是在C++11新标准中提出的。在lambda表达式中,我们集中梳理了一下它的使用。现在来讨论下它的实现原理。

    正文
    1.函数对象
    类的对象跟括号结合,表现出函数一般的行为,这个对象可以称作是函数对象。

    #include <iostream>
    using namespace std;
    class MyClass
    {
      public:
      //重载函数调用运算符()
      int operator()(int i)
      {
        return i;
      }
    };
    int main()
    {
      MyClass my;
      //my()的调用行为似同函数
      int i = my(1); //本质是调用 my.operator()(1)
      cout << "i = " << i << endl;
      cin.get();
      return 0;
    }
    运行


    这个示例说明函数对象的本质是重载了函数调用运算符。当一个类重载了函数调用运算符()后,它的对象就成了函数对象。这是理解lambda表达式内部实现的基础。

    2.lambda表达式原理
    原理:编译器会把一个lambda表达式生成一个匿名类的匿名对象,并在类中重载函数调用运算符。

    我们从最简单的lambda表达式入手,从易到难

    2.1 无捕获列表和参数列表
    auto print = []{cout << "zhangxiang" << endl; };
    编译器会把这一句翻译成如下情形:
    //用给定的lambda表达式生成相应的类
    class print_class
    {
      public:
      void operator()(void) const
      {  
        cout << "zhangxiang" << endl;
      }
    };
    //用构造的类创建对象,print此时就是一个函数对象
    auto print = print_class();
    生成类的类名命名规则可以多变,不一定非得这样。


    2.2 无捕获列表但有参数列表
    auto add = [](int a, int b){return a + b; };
    编译器会把这一句翻译成如下情形:
    class add_class
    {
      public:
      auto operator()(int a, int b) const
      {
        return a + b;
      }
    };
    auto add = add_class();


    2.3 有捕获列表,参数列表可选
    由于捕获方式分为两种:引用捕获、值捕获,故此种情况下,又可细分。

    2.3.1 值捕获
    int year = 19900212;
    char *name = "zhangxiang";
    //采用值捕获,捕获所有的已定义的局部变量,如year,name
    auto print = [=](){
    cout << year << ends << name << endl;
    };
    翻译
    int year = 19900212;
    char *name = "zhangxiang";
    class print_class
    {
      public:
      //根据捕获列表来决定构造函数的参数列表形式
      print_class(int year, char *name) :year(year), name(name)
      {

      }
      void operator()(void) const
      {
        cout << year << ends << name << endl;
      }
      private:
      int year;
      char *name;
    };
    auto print = print_class(a, str);
    运行效果是一样的,就不演示了。


    2.3.2 引用捕获
    int year = 19900212;
    char *name = "zhangxiang";
    auto print = [&](){
      year++;
      cout << year << ends << name << endl;
    };
    翻译
    int year = 19900212;
    char *name = "zhangxiang";
    class print_class
    {
      public:
      //由于是引用捕获,参数列表采用引用的方式
      print_class(int &year, char *&name) :year(year), name(name)
      {

      }
      void operator()(void) const
      {
        year++; //编译通过,const对引用类型无效
        cout << year << ends << name << endl;
      }
      private:
        int &year;
        char *&name;
    };
    经过测试,效果也是一样的。

    2.3.3 混合捕获
    int year = 19900212;
    int shoes = 42;
    char *name = "zhangxiang";
    auto show = [&, shoes]()mutable{
      shoes++;
      year++;
      cout << year << ends << shoes << ends << name << endl;
    };
    翻译
    int year = 19900212;
    int shoes = 42;
    char *name = "zhangxiang";
    class show_class
    {
      private:
      int &year;
      mutable int shoes;
      char *&name;
      public:
      show_class(int &year, int shoes, char *&name) :year(year), shoes(shoes), name(name)
      {

      }
      void operator()(void)const
      {
        shoes++;
        year++;
        cout << year << ends << shoes << ends << name << endl;
      }
    };
    auto show = show_class(year, shoes, name);
    show();


    默认情况下,经过值捕获的变量是不可以被修改的,除非在参数列表后加关键字mutable。以上代码展示了,对应类中mutable是如何加的。当然还有另一种实现方法,只要lambda表达式加了mutable,重载函数调用运算符时就不加const修饰。


    总结
    以上这些示例代码基本上把各种情形的lambda表达式的实现原理都展现出来了,仔细想想还是挺容易的。
    ————————————————
    版权声明:本文为CSDN博主「苏叔叔」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
    原文链接:https://blog.csdn.net/zhangxiangdavaid/article/details/44064765

  • 相关阅读:
    认知实习(杭钢、杭州中萃)
    Head of a Gang (map+邻接表+DFS)
    Sharing
    Hello World for U (20)
    计算器(delphi)
    CentOS 下 Codeblocks 的 安装 + 汉化 以及 基本使用介绍
    关于阿里如何吸引大学生用户理财的一些个人看法
    分页 存储过程
    点击退出,并未直接跳转到登陆界面,登录界面还停留在框架集界面
    梦幻之旅--地图编辑器开发
  • 原文地址:https://www.cnblogs.com/bruce1992/p/15219982.html
Copyright © 2020-2023  润新知