C++ lambda表达式的使用(更新中)

什么是lambda

lambda表达式(Anonymous function)是匿名函数,没有具体的函数名,一个lambda表达式表示一个可调用的代码单元,我们可以将它理解为未命名的内联函数(摘自C++ primer 5),一个lambda表达式具有一个返回类型,一个参数列表和一个函数体.
一个lambda的具体形式如下:
[ c a p t u r e   l i s t ]    ( p a r a m e t e r   l i s t ) − > [ r e t u r n   t y p e ] {   f u n c t i o n   b o d y   } [capture\ list]\ \ (parameter\ list) ->[return\ type]\{\ function\ body\ \} [capture list]  (parameter list)>[return type]{ function body }

lambda表达式的使用

 auto func = [] { return true }//忽略参数列表和返回类型,func则为可调用对象,不接受参数,返回true
 auto func1 = [](const int &n){ return n > 0 ? true : false; };//判断n是否大于0
  if (func(-2)) {
    std::cout << "true" << std::endl;
  }

捕获列表使用
lambda表达式中的捕获分为值捕获和引用捕获,[]空捕获列表,[=]隐式值捕获列表,[&]隐式引用捕获列表
捕获很好理解,类似于传值参数,使用值捕获时,并不是在lambda被调用的时候才会捕获,而是lambda创建时捕获

  std::string test_message("good!");
  //空捕获列表的lambda
  auto show_capture1 = [] {
    std::cout << "1: null capture" << std::endl;
    return 0;
  };
  //隐式值捕获列表的lambda,此时lambda可以捕获当前空间内的所有变量
  auto show_capture2 = [=] {
    std::cout << "2: values capture\t" << test_message << std::endl;
  };
  //隐式引用捕获列表的lambda,此时lambda可以捕获当前空间内所有变量的引用
  auto show_capture3 = [&] {
    std::cout << "3: reference capture\t" << test_message << std::endl;
    test_message = "awesome!";
  };
  //引用捕获test_message
  auto show_capture4 = [&test_message] {
    std::cout << "4: " << test_message << std::endl;
    test_message = "bad!";
  };
  //值捕获test_message
  auto show_capture5 = [test_message] {
    std::cout << "5: " << test_message << std::endl;
    // test_message = "123";  这条语句编译错误具体错误看下文error1
  };
  //引用不糊test_message,其他变量采用值捕获
  auto show_capture6 = [=, &test_message] {
    std::cout << "6: " << test_message << std::endl;
  };
  //引用捕获其他变量,值捕获test_message
  auto show_capture7 = [&, test_message] {
    std::cout << "7: " << test_message << std::endl;
  };

  show_capture1();
  show_capture2();
  show_capture3();
  show_capture4();
  show_capture5();
  show_capture6();
  show_capture7();
输出:
1: null capture
2: values capture       good!
3: reference capture    good!
4: awesome!
5: good!
6: bad!
7: good!

分析上述代码:
1.由于前面说过,lambda值捕获是在lambda创建的时候进行的,当show_capture 2 5 7这三个lambda被调用时候,test_message的值为前面定义时候的值"good!".
2.当show_capture3被调用是,test_message的值为"good!“所以输出为"good!”,随后test_message的值被修改为"awesome!"
3.show_capture4传入的是test_message的引用,由于被3修改成"awesome!“所以输出为"awesome!”,随后test_message被修改为"bad!"
4.同上,当show_capture6被调用是,输出"bad!“因为test_message的值已经被show_capture4修改成"bad!”

值捕获相关error

list_learn.cc: In lambda function:
list_learn.cc:65:17: error: passing ‘const string {aka const std::__cxx11::basic_string}’ as ‘this’ argument discards qualifiers [-fpermissive]
     test_message="123";
                 ^
In file included from /usr/include/c++/5/string:52:0,
                 from /usr/include/c++/5/bits/locale_classes.h:40,
                 from /usr/include/c++/5/bits/ios_base.h:41,
                 from /usr/include/c++/5/ios:42,
                 from /usr/include/c++/5/ostream:38,
                 from /usr/include/c++/5/iostream:39,
                 from list_learn.cc:1:
/usr/include/c++/5/bits/basic_string.h:558:7: note:   in call to ‘std::__cxx11::basic_string<_CharT, _Traits, _Alloc>& std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::operator=(const _CharT*) [with _CharT = char; _Traits = std::char_traits; _Alloc = std::allocator]’
       operator=(const _CharT* __s)

出先上述错误的原因是我在show_capture5函数体里面对值捕获的test_message进行重新赋值是产生.
通过编译器看到错误提示为:

no operator “=” matches these operands – operand types are: const std::__cxx11::string = const char [4]

这里test_message的值拷贝是常量吗?
于是我修改一下代码,看看其他类型的值捕获会有什么奇怪的表现

  std::string test_message("good!");
  test_message="123";
  int x=0;
    auto show_capture5 = [x,test_message] {
    std::cout << "5: " << test_message << std::endl;
    // test_message="123";
    x=123;// 这里提示expression must be a modifiable lvalue

  };

这里说明x是一个不可以修改或者是一个右值,导致无法进行赋值.
查了一些博客,这篇博客提到:
Lambda表达式是通过生成一个小class实现的,这个类重载了operater()函数,所以它的行为非常像一个函数。Lambda函数就是这个class的实例;当这个类构造时,上下文中的任何变量都可以传进Lambda function class,并作为成员变量保存起来。这事实上这有点像一个已经存在的functor(仿函数)。这样就解决了我的问题,Capture用于传递上下文的环境变量,在class的构造函数中使用;Parameter list是operator()函数的参数列表。

因此我猜测,这个小class的所有成员变量都是被const修饰的,于是我尝试修改test_message的定义

const std::string test_message("good!");
test_message = "123";//提示错误 no operator "=" matches these operands -- operand types are: const std::__cxx11::string = const char [4]

编译时也是出现上述error,因此证明lambda的类实现里所有成员变量都是被const修饰的变量,其实这个问题查看lambda实现的原码就可以解,或者动脑子想想,修改值传递的拷贝值并没有意义,若要真正修改该变量的内容,可以采用引用捕获.

你可能感兴趣的:(C++学习)