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放置的地方哦!!!