什么是C ++ 11中的lambda表达式?

本文翻译自:What is a lambda expression in C++11?

What is a lambda expression in C++11? 什么是C ++ 11中的lambda表达式? When would I use one? 我什么时候用一个? What class of problem do they solve that wasn't possible prior to their introduction? 在引入之前,他们无法解决什么问题?

A few examples, and use cases would be useful. 一些示例和用例将很有用。


#1楼

参考:https://stackoom.com/question/W09i/什么是C-中的lambda表达式


#2楼

Lambda expressions are typically used to encapsulate algorithms so that they can be passed to another function. Lambda表达式通常用于封装算法,以便可以将它们传递给另一个函数。 However, it is possible to execute a lambda immediately upon definition : 但是, 可以在定义后立即执行lambda

[&](){ ...your code... }(); // immediately executed lambda expression

is functionally equivalent to 在功能上等同于

{ ...your code... } // simple code block

This makes lambda expressions a powerful tool for refactoring complex functions . 这使lambda表达式成为重构复杂函数的强大工具 You start by wrapping a code section in a lambda function as shown above. 首先,将代码段包装在lambda函数中,如上所示。 The process of explicit parameterization can then be performed gradually with intermediate testing after each step. 然后,可以在每个步骤之后通过中间测试逐步执行显式参数化的过程。 Once you have the code-block fully parameterized (as demonstrated by the removal of the & ), you can move the code to an external location and make it a normal function. 将代码块完全参数化后(如删除& ),可以将代码移至外部位置并将其设为正常功能。

Similarly, you can use lambda expressions to initialize variables based on the result of an algorithm ... 同样,您可以使用lambda表达式根据算法的结果初始化变量 ...

int a = []( int b ){ int r=1; while (b>0) r*=b--; return r; }(5); // 5!

As a way of partitioning your program logic , you might even find it useful to pass a lambda expression as an argument to another lambda expression... 作为分区程序逻辑的一种方法 ,您甚至可能发现将lambda表达式作为参数传递给另一个lambda表达式很有用...

[&]( std::function<void()> algorithm ) // wrapper section
   {
   ...your wrapper code...
   algorithm();
   ...your wrapper code...
   }
([&]() // algorithm section
   {
   ...your algorithm code...
   });

Lambda expressions also let you create named nested functions , which can be a convenient way of avoiding duplicate logic. Lambda表达式还允许您创建命名的嵌套函数 ,这是避免重复逻辑的便捷方法。 Using named lambdas also tends to be a little easier on the eyes (compared to anonymous inline lambdas) when passing a non-trivial function as a parameter to another function. 当将非平凡的函数作为参数传递给另一个函数时,使用命名的lambda往往也更容易(与匿名内联lambda相比)。 Note: don't forget the semicolon after the closing curly brace. 注意:不要忘了在大括号后加上分号。

auto algorithm = [&]( double x, double m, double b ) -> double
   {
   return m*x+b;
   };

int a=algorithm(1,2,3), b=algorithm(4,5,6);

If subsequent profiling reveals significant initialization overhead for the function object, you might choose to rewrite this as a normal function. 如果后续分析显示出该函数对象的大量初始化开销,则可以选择将其重写为普通函数。

扫描二维码关注公众号,回复: 10411964 查看本文章

#3楼

A lambda function is an anonymous function that you create in-line. Lambda函数是您直接创建的匿名函数。 It can capture variables as some have explained, (eg http://www.stroustrup.com/C++11FAQ.html#lambda ) but there are some limitations. 正如某些人所解释的那样,它可以捕获变量(例如, http : //www.stroustrup.com/C++11FAQ.html#lambda ),但是存在一些限制。 For example, if there's a callback interface like this, 例如,如果有这样的回调接口,

void apply(void (*f)(int)) {
    f(10);
    f(20);
    f(30);
}

you can write a function on the spot to use it like the one passed to apply below: 您可以当场编写一个函数来使用它,就像下面传递的那样:

int col=0;
void output() {
    apply([](int data) {
        cout << data << ((++col % 10) ? ' ' : '\n');
    });
}

But you can't do this: 但是您不能这样做:

void output(int n) {
    int col=0;
    apply([&col,n](int data) {
        cout << data << ((++col % 10) ? ' ' : '\n');
    });
}

because of limitations in the C++11 standard. 由于C ++ 11标准的局限性。 If you want to use captures, you have to rely on the library and 如果要使用捕获,则必须依赖库

#include <functional> 

(or some other STL library like algorithm to get it indirectly) and then work with std::function instead of passing normal functions as parameters like this: (或其他一些类似算法的STL库来间接获取它),然后使用std :: function而不是像这样将普通函数作为参数传递:

#include <functional>
void apply(std::function<void(int)> f) {
    f(10);
    f(20);
    f(30);
}
void output(int width) {
    int col;
    apply([width,&col](int data) {
        cout << data << ((++col % width) ? ' ' : '\n');
    });
}

#4楼

Answers 答案

Q: What is a lambda expression in C++11? 问:C ++ 11中的lambda表达式是什么?

A: Under the hood, it is the object of an autogenerated class with overloading operator() const . 答:在后台,它是带有重载operator()const的自动生成类的对象。 Such object is called closure and created by compiler. 这种对象称为闭包 ,由编译器创建。 This 'closure' concept is near with the bind concept from C++11. 这个“关闭”概念与C ++ 11的bind概念差不多。 But lambdas typically generate better code. 但是lambda通常会生成更好的代码。 And calls through closures allow full inlining. 通过闭包的调用允许完整的内联。

Q: When would I use one? 问:我什么时候会用一次?

A: To define "simple and small logic" and ask compiler perform generation from previous question. 答:要定义“简单逻辑”,并要求编译器根据上一个问题进行生成。 You give a compiler some expressions which you want to be inside operator(). 您为编译器提供了一些要包含在operator()中的表达式。 All other stuff compiler will generate to you. 所有其他的东西编译器都会为您生成。

Q: What class of problem do they solve that wasn't possible prior to their introduction? 问:在介绍之前,他们无法解决哪种问题?

A: It is some kind of syntax sugar like operators overloading instead of functions for custom add, subrtact operations...But it save more lines of unneeded code to wrap 1-3 lines of real logic to some classes, and etc.! 答:这是一种语法糖,例如运算符重载,而不是自定义添加,子操作的函数……但是它节省了更多的不需要的代码行,可以将1-3行的实际逻辑包装到某些类中,等等! Some engineers think that if the number of lines is smaller then there is a less chance to make errors in it (I'm also think so) 一些工程师认为,如果行数较少,那么出错的机会就更少了(我也这么认为)

Example of usage 使用例

auto x = [=](int arg1){printf("%i", arg1); };
void(*f)(int) = x;
f(1);
x(1);

Extras about lambdas, not covered by question. 有关lambda的其他内容,不在问题范围之内。 Ignore this section if you're not interest 如果您不感兴趣,请忽略此部分

1. Captured values. 1.捕获的值。 What you can to capture 您可以捕获什么

1.1. 1.1。 You can reference to a variable with static storage duration in lambdas. 您可以使用lambdas引用具有静态存储持续时间的变量。 They all are captured. 他们全部被捕获。

1.2. 1.2。 You can use lambda for capture values "by value". 您可以使用lambda来“按值”捕获值。 In such case captured vars will be copied to the function object (closure). 在这种情况下,捕获的变量将被复制到函数对象(关闭)。

[captureVar1,captureVar2](int arg1){}

1.3. 1.3。 You can capture be reference. 您可以参考。 & -- in this context mean reference, not pointers. &-在本文中是指引用,而不是指针。

   [&captureVar1,&captureVar2](int arg1){}

1.4. 1.4。 It exists notation to capture all non-static vars by value, or by reference 它具有表示法,可以按值或按引用捕获所有非静态变量

  [=](int arg1){} // capture all not-static vars by value

  [&](int arg1){} // capture all not-static vars by reference

1.5. 1.5。 It exists notation to capture all non-static vars by value, or by reference and specify smth. 它存在一种表示法,可以按值或按引用捕获所有非静态var并指定smth。 more. 更多。 Examples: Capture all not-static vars by value, but by reference capture Param2 示例:通过值捕获所有非静态变量,但通过引用捕获Param2

[=,&Param2](int arg1){} 

Capture all not-static vars by reference, but by value capture Param2 通过引用捕获所有非静态变量,但通过值捕获Param2

[&,Param2](int arg1){} 

2. Return type deduction 2.返回类型扣除

2.1. 2.1。 Lambda return type can be deduced if lambda is one expression. 如果lambda是一个表达式,则可以推断出lambda返回类型。 Or you can explicitly specify it. 或者您可以显式指定它。

[=](int arg1)->trailing_return_type{return trailing_return_type();}

If lambda has more then one expression, then return type must be specified via trailing return type. 如果lambda具有多个表达式,则必须通过尾随返回类型指定返回类型。 Also, similar syntax can be applied to auto functions and member-functions 同样,类似的语法可以应用于自动功能和成员功能

3. Captured values. 3.捕获的值。 What you can not capture 您无法捕获的内容

3.1. 3.1。 You can capture only local vars, not member variable of the object. 您只能捕获本地var,而不能捕获对象的成员变量。

4. Сonversions 4.转换

4.1 !! 4.1 !! Lambda is not a function pointer and it is not an anonymous function, but capture-less lambdas can be implicitly converted to a function pointer. Lambda不是函数指针,也不是匿名函数,但是可以将无捕获的 Lambda隐式转换为函数指针。

ps ps

  1. More about lambda grammar information can be found in Working draft for Programming Language C++ #337, 2012-01-16, 5.1.2. 有关lambda语法信息的更多信息,请参见《 C ++编程语言》工作草案#337、2012-01-16、5.1.2。 Lambda Expressions, p.88 Lambda表达式,第88页

  2. In C++14 the extra feature which has named as "init capture" have been added. 在C ++ 14中,添加了名为“初始捕获”的额外功能。 It allow to perform arbitarily declaration of closure data members: 它允许任意执行闭包数据成员的声明:

     auto toFloat = [](int value) { return float(value);}; auto interpolate = [min = toFloat(0), max = toFloat(255)](int value)->float { return (value - min) / (max - min);}; 

#5楼

One problem it solves: Code simpler than lambda for a call in constructor that uses an output parameter function for initializing a const member 它解决的一个问题是: 在构造函数中使用输出参数函数初始化const成员的调用的代码比lambda更简单

You can initialize a const member of your class, with a call to a function that sets its value by giving back its output as an output parameter. 您可以通过调用返回其输出作为输出参数来设置其值的函数来初始化类的const成员。


#6楼

Well, one practical use I've found out is reducing boiler plate code. 好吧,我发现的一种实际用途是减少样板代码。 For example: 例如:

void process_z_vec(vector<int>& vec)
{
  auto print_2d = [](const vector<int>& board, int bsize)
  {
    for(int i = 0; i<bsize; i++)
    {
      for(int j=0; j<bsize; j++)
      {
        cout << board[bsize*i+j] << " ";
      }
      cout << "\n";
    }
  };
  // Do sth with the vec.
  print_2d(vec,x_size);
  // Do sth else with the vec.
  print_2d(vec,y_size);
  //... 
}

Without lambda, you may need to do something for different bsize cases. 如果没有lambda,则可能需要为不同的bsize情况做一些事情。 Of course you could create a function but what if you want to limit the usage within the scope of the soul user function? 当然,您可以创建一个函数,但是如果您想在灵魂用户函数的范围内限制使用该怎么办? the nature of lambda fulfills this requirement and I use it for that case. lambda的性质满足了此要求,在这种情况下,我会使用它。

发布了0 篇原创文章 · 获赞 7 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/asdfgh0077/article/details/105225723