lambda expression & mutable

一、Lambda表达式定义

  

二、Lambda捕获方式

  

三、Lambda使用

 1 void main()
 2 {
 3     int a = 1, b = 2;
 4     auto fn1 = []() {std::cout << "fn1\n"; };
 5     // auto fn1 = []() {std::cout << "fn1()" << a << "\n"; }; // Error1
 6     auto fn2 = [](int m, int n) {std::cout << "fn2(a, b) = " << m + n << "\n"; };
 7     auto fn3 = [](int m, int n)->int {return m + n; };
 8     // auto fn3 = [](int a, int b) {return a + b; } // Error2
 9     auto fn4 = [&]()->int {a = 10; b = 20; return a + b; }; 
10     // auto fn4 = [=]()->int {a = 10; b = 20; return a + b; }; // Error3
11     auto fn5 = [=]()->int {return a + b; };
12     auto fn6 = [a, &b]()->int {b = 20; return a + b; };
13     // auto fn6 = [a, &b]()->int {a = 10; b = 20; return a + b; }; // Error4
14 
15     fn1();
16     fn2(a, b);
17     fn3(a, b);
18     fn4();
19     fn5();
20     fn6();
21 }
  • [] 可以为空,默认不捕获任何变量
  • [&]对Lambda表达式可见的变量进行引用捕获
  • [=]对Lambda表达式可见的变量进行之捕获
  • [a, &b]对指定的变量进行值或引用捕获

  是否注意到被注释的代码部分,这些都是错误的写法。Error1:Lambda表达式未捕获任何变量,所以其内部不可使用外部的变量;Error2(3, 4):Lambda表达式内部不可对值捕获的变量进行修改,如果需要修改需要使用另外的方式。通过上面错误例子

引出今天的主题:为什么Lambda表达式值捕获的变量不可在其内部修改?如果需要修改,改如何实现?

四、Lambda & mutable

  看如下定义的函数:

1 void Func(int a)
2 {
3     a = 10;
4     std::cout << "a = " << a << std::endl;
5 }

  调用者通过值传递的方式调用Func,在函数内部可以修改形参变量a,但是不影响实参a;这个原理大家都懂,就不介绍了。恰恰这个问题的引入,让我们想到,Lambda表达式的值捕获和形参值传递是一样的,即副本机制;但是Lambda就不能在其

内部修改呢?这个疑问还得从闭包说起,啥是闭包,请自行Google。简言之,我们在代码中定义Lambda函数时,编译器在编译的时候并不将该Lambda函数直接替换成函数,而是一个对象,注意这里说的是对象;这个对象通过操作符operator()()实现函数的调用,这是不是很熟悉?没错,这就是函数对象。再看如下的代码:

 1 struct unamed1
 2 {
 3     int param;
 4     unamed1(int a) : param(a) {}
 5     void operator()() const {
 6         //param = 10; // Error
 7         std::cout << "param " << param << std::endl;
 8     }
 9 };
10 
11 struct unamed2
12 {
13     int& param;
14     unamed2(int& a) : param(a) {}
15     void operator()() const {
16         param = 10;  // OK
17         std::cout << "param " << param << std::endl;
18     }
19 };
20 
21 struct unamed3
22 {
23     int param;
24     unamed3(int a) : param(a) {}
25     void operator()(){
26         param = 10;  // OK
27         std::cout << "param " << param << std::endl;
28     }
29 };

  是不是就”悟“呢?从C++标准草案(http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2011/n3242.pdf)中也可以找到这个问题的答案:

      

  如果我们想对值捕获的变量进行修改,该怎么处理呢?使用mutable修饰。从C++标准文档(https://en.cppreference.com/w/cpp/language/lambda)可以看到如下说明:

  验证如下:

1 void main()
2 {
3     int a = 1, b = 2;
4 
5     auto fn = [=]() mutable {a = 10; b = 20; std::cout << "fn(a, b) = " << a + b << "\n"; };
6     fn();
7 }

   

   这里需要注意mutable放置的地方哦!!!

posted @ 2021-04-21 18:18  blackstar666  阅读(79)  评论(0编辑  收藏  举报