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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/7627098/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-28 17:15:31  来源:igfitidea点击:

What is a lambda expression in C++11?

c++lambdac++11c++-faq

提问by Nawaz

What is a lambda expression in C++11? When would I use one? What class of problem do they solve that wasn't possible prior to their introduction?

什么是 C++11 中的 lambda 表达式?我什么时候用一个?他们解决了哪些在引入之前无法解决的问题?

A few examples, and use cases would be useful.

一些例子和用例会很有用。

回答by Flexo

The problem

问题

C++ includes useful generic functions like std::for_eachand std::transform, which can be very handy. Unfortunately they can also be quite cumbersome to use, particularly if the functoryou would like to apply is unique to the particular function.

C++ 包括有用的通用函数,如std::for_eachand std::transform,它们非常方便。不幸的是,它们使用起来也很麻烦,特别是如果您要应用的函子是特定函数所独有的。

#include <algorithm>
#include <vector>

namespace {
  struct f {
    void operator()(int) {
      // do something
    }
  };
}

void func(std::vector<int>& v) {
  f f;
  std::for_each(v.begin(), v.end(), f);
}

If you only use fonce and in that specific place it seems overkill to be writing a whole class just to do something trivial and one off.

如果你只f在那个特定的地方使用一次,那么编写一整个类只是为了做一些微不足道的事情似乎有点过分。

In C++03 you might be tempted to write something like the following, to keep the functor local:

在 C++03 中,您可能会想写如下内容,以保持函子本地化:

void func2(std::vector<int>& v) {
  struct {
    void operator()(int) {
       // do something
    }
  } f;
  std::for_each(v.begin(), v.end(), f);
}

however this is not allowed, fcannot be passed to a templatefunction in C++03.

但是这是不允许的,f不能传递给C++03 中的模板函数。

The new solution

新的解决方案

C++11 introduces lambdas allow you to write an inline, anonymous functor to replace the struct f. For small simple examples this can be cleaner to read (it keeps everything in one place) and potentially simpler to maintain, for example in the simplest form:

C++11 引入了 lambdas 允许你编写一个内联的匿名函子来替换struct f. 对于小的简单示例,这可以更清晰地阅读(它将所有内容放在一个地方)并且可能更易于维护,例如以最简单的形式:

void func3(std::vector<int>& v) {
  std::for_each(v.begin(), v.end(), [](int) { /* do something here*/ });
}

Lambda functions are just syntactic sugar for anonymous functors.

Lambda 函数只是匿名函子的语法糖。

Return types

返回类型

In simple cases the return type of the lambda is deduced for you, e.g.:

在简单的情况下,为您推导出 lambda 的返回类型,例如:

void func4(std::vector<double>& v) {
  std::transform(v.begin(), v.end(), v.begin(),
                 [](double d) { return d < 0.00001 ? 0 : d; }
                 );
}

however when you start to write more complex lambdas you will quickly encounter cases where the return type cannot be deduced by the compiler, e.g.:

但是,当您开始编写更复杂的 lambda 表达式时,您很快就会遇到编译器无法推断出返回类型的情况,例如:

void func4(std::vector<double>& v) {
    std::transform(v.begin(), v.end(), v.begin(),
        [](double d) {
            if (d < 0.0001) {
                return 0;
            } else {
                return d;
            }
        });
}

To resolve this you are allowed to explicitly specify a return type for a lambda function, using -> T:

要解决此问题,您可以使用以下命令显式指定 lambda 函数的返回类型-> T

void func4(std::vector<double>& v) {
    std::transform(v.begin(), v.end(), v.begin(),
        [](double d) -> double {
            if (d < 0.0001) {
                return 0;
            } else {
                return d;
            }
        });
}

"Capturing" variables

“捕获”变量

So far we've not used anything other than what was passed to the lambda within it, but we can also use other variables, within the lambda. If you want to access other variables you can use the capture clause (the []of the expression), which has so far been unused in these examples, e.g.:

到目前为止,除了传递给其中的 lambda 之外,我们还没有使用任何其他东西,但我们也可以在 lambda 中使用其他变量。如果您想访问其他变量,您可以使用 capture 子句([]表达式的 the),到目前为止这些示例中尚未使用该子句,例如:

void func5(std::vector<double>& v, const double& epsilon) {
    std::transform(v.begin(), v.end(), v.begin(),
        [epsilon](double d) -> double {
            if (d < epsilon) {
                return 0;
            } else {
                return d;
            }
        });
}

You can capture by both reference and value, which you can specify using &and =respectively:

您可以通过引用和值来捕获,您可以分别使用&和指定它们=

  • [&epsilon]capture by reference
  • [&]captures all variables used in the lambda by reference
  • [=]captures all variables used in the lambda by value
  • [&, epsilon]captures variables like with [&], but epsilon by value
  • [=, &epsilon]captures variables like with [=], but epsilon by reference
  • [&epsilon]按引用捕获
  • [&]通过引用捕获 lambda 中使用的所有变量
  • [=]按值捕获 lambda 中使用的所有变量
  • [&, epsilon]使用 [&] 捕获变量,但按值捕获 epsilon
  • [=, &epsilon]像 [=] 一样捕获变量,但通过引用来捕获 epsilon

The generated operator()is constby default, with the implication that captures will be constwhen you access them by default. This has the effect that each call with the same input would produce the same result, however you can mark the lambda as mutableto request that the operator()that is produced is not const.

生成的operator()const默认的,这意味着const默认情况下您访问它们时会进行捕获。这会导致具有相同输入的每次调用都会产生相同的结果,但是您可以将 lambda 标记为mutable请求operator()生成的不是const

回答by pmr

What is a lambda function?

什么是 lambda 函数?

The C++ concept of a lambda function originates in the lambda calculus and functional programming. A lambda is an unnamed function that is useful (in actual programming, not theory) for short snippets of code that are impossible to reuse and are not worth naming.

lambda 函数的 C++ 概念起源于 lambda 演算和函数式编程。lambda 是一个未命名的函数,对于无法重用且不值得命名的短代码片段很有用(在实际编程中,而不是理论上)。

In C++ a lambda function is defined like this

在 C++ 中,一个 lambda 函数是这样定义的

[]() { } // barebone lambda

or in all its glory

或在它所有的荣耀中

[]() mutable -> T { } // T is the return type, still lacking throw()

[]is the capture list, ()the argument list and {}the function body.

[]是捕获列表、()参数列表和{}函数体。

The capture list

捕获列表

The capture list defines what from the outside of the lambda should be available inside the function body and how. It can be either:

捕获列表定义了 lambda 外部的哪些内容应该在函数体内可用以及如何使用。它可以是:

  1. a value: [x]
  2. a reference [&x]
  3. any variable currently in scope by reference [&]
  4. same as 3, but by value [=]
  1. 一个值:[x]
  2. 参考 [&x]
  3. 当前在引用范围内的任何变量 [&]
  4. 与 3 相同,但按值 [=]

You can mix any of the above in a comma separated list [x, &y].

您可以在逗号分隔列表中混合上述任何内容[x, &y]

The argument list

参数列表

The argument list is the same as in any other C++ function.

参数列表与任何其他 C++ 函数中的相同。

The function body

函数体

The code that will be executed when the lambda is actually called.

实际调用 lambda 时将执行的代码。

Return type deduction

退货类型扣除

If a lambda has only one return statement, the return type can be omitted and has the implicit type of decltype(return_statement).

如果 lambda 只有一个 return 语句,则可以省略返回类型并具有 隐式类型decltype(return_statement)

Mutable

可变的

If a lambda is marked mutable (e.g. []() mutable { }) it is allowed to mutate the values that have been captured by value.

如果 lambda 被标记为可变的(例如[]() mutable { }),则允许改变已被值捕获的值。

Use cases

用例

The library defined by the ISO standard benefits heavily from lambdas and raises the usability several bars as now users don't have to clutter their code with small functors in some accessible scope.

ISO 标准定义的库从 lambda 中受益匪浅,并提高了几个方面的可用性,因为现在用户不必在某些可访问的范围内用小函子来混乱他们的代码。

C++14

C++14

In C++14 lambdas have been extended by various proposals.

在 C++14 中,各种提议都扩展了 lambda。

Initialized Lambda Captures

初始化的 Lambda 捕获

An element of the capture list can now be initialized with =. This allows renaming of variables and to capture by moving. An example taken from the standard:

捕获列表的元素现在可以使用=. 这允许重命名变量并通过移动进行捕获。取自标准的一个例子:

int x = 4;
auto y = [&r = x, x = x+1]()->int {
            r += 2;
            return x+2;
         }();  // Updates ::x to 6, and initializes y to 7.

and one taken from Wikipedia showing how to capture with std::move:

和来自维基百科的一个显示如何捕获std::move

auto ptr = std::make_unique<int>(10); // See below for std::make_unique
auto lambda = [ptr = std::move(ptr)] {return *ptr;};

Generic Lambdas

通用 Lambda

Lambdas can now be generic (autowould be equivalent to There if Twere a type template argument somewhere in the surrounding scope):

Lambda 现在可以是泛型的(如果是周围范围内某处的类型模板参数,则auto相当于T此处 T):

auto lambda = [](auto x, auto y) {return x + y;};

Improved Return Type Deduction

改进的返回类型推导

C++14 allows deduced return types for every function and does not restrict it to functions of the form return expression;. This is also extended to lambdas.

C++14 允许为每个函数推导出返回类型,并且不将其限制为形式为 的函数return expression;。这也扩展到 lambdas。

回答by nobar

Lambda expressions are typically used to encapsulate algorithms so that they can be passed to another function. However, it is possible to execute a lambda immediately upon definition:

Lambda 表达式通常用于封装算法,以便将它们传递给另一个函数。但是,可以在定义后立即执行 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. You start by wrapping a code section in a lambda function as shown above. 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.

这使得 lambda 表达式成为重构复杂函数的强大工具。您首先将代码部分包装在 lambda 函数中,如上所示。然后可以在每个步骤之后通过中间测试逐渐执行显式参数化过程。一旦您将代码块完全参数化(如删除 所示&),您就可以将代码移动到外部位置并使其成为正常函数。

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. 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. Note: don't forget the semicolon after the closing curly brace.

Lambda 表达式还允许您创建命名嵌套函数,这是一种避免重复逻辑的便捷方式。在将非平凡函数作为参数传递给另一个函数时,使用命名 lambda 也往往更容易一些(与匿名内联 lambda 相比)。 注意:不要忘记右花括号后面的分号。

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.

如果随后的分析揭示了函数对象的大量初始化开销,您可以选择将其重写为普通函数。

回答by bruziuz

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. Such object is called closureand created by compiler. This 'closure' concept is near with the bind concept from C++11. But lambdas typically generate better code. And calls through closures allow full inlining.

答:在幕后,它是重载operator() const的自动生成类的对象。这样的对象称为闭包,由编译器创建。这个“闭包”概念与 C++11 中的绑定概念很接近。但是 lambdas 通常会生成更好的代码。通过闭包调用允许完全内联。

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(). All other stuff compiler will generate to you.

A:定义“简单小逻辑”并要求编译器从上一个问题执行生成。你给编译器一些你想要在 operator() 中的表达式。所有其他东西编译器都会生成给你。

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, subrtactoperations...But it save more lines of unneeded code to wrap 1-3 lines of real logic to some classes, and etc.! 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)

A:它是某种语法糖,例如运算符重载而不是用于自定义加法、减法运算的函数……但它节省了更多不需要的代码行以将 1-3 行真实逻辑包装到某些类中,等等!一些工程师认为,如果行数越少,那么出错的机会就越少(我也这么认为)

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. Ignore this section if you're not interest

关于 lambda 的额外内容,未包含在问题中。如果您不感兴趣,请忽略此部分

1. Captured values. What you can to capture

1. 捕获的值。你可以捕捉什么

1.1. You can reference to a variable with static storage duration in lambdas. They all are captured.

1.1. 您可以在 lambda 中引用具有静态存储持续时间的变量。他们都被俘虏了。

1.2. You can use lambda for capture values "by value". In such case captured vars will be copied to the function object (closure).

1.2. 您可以使用 lambda 来“按值”捕获值。在这种情况下,捕获的变量将被复制到函数对象(闭包)。

[captureVar1,captureVar2](int arg1){}

1.3. You can capture be reference. & -- in this context mean reference, not pointers.

1.3. 可以抓拍参考。& -- 在此上下文中表示引用,而不是指针。

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

1.4. It exists notation to capture all non-static vars by value, or by reference

1.4. 它存在按值或按引用捕获所有非静态变量的符号

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

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

1.5. It exists notation to capture all non-static vars by value, or by reference and specify smth. more. Examples: Capture all not-static vars by value, but by reference capture Param2

1.5. 它存在按值或按引用捕获所有非静态变量并指定 smth 的符号。更多的。示例:按值捕获所有非静态变量,但按引用捕获 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. Lambda return type can be deduced if lambda is one expression. Or you can explicitly specify it.

2.1. 如果 lambda 是一个表达式,则可以推导出 Lambda 返回类型。或者您可以明确指定它。

[=](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. Also, similar syntax can be applied to auto functions and member-functions

如果 lambda 有多个表达式,则必须通过尾随返回类型指定返回类型。此外,类似的语法可以应用于自动函数和成员函数

3. Captured values. What you can not capture

3. 捕获的值。你无法捕捉的东西

3.1. You can capture only local vars, not member variable of the object.

3.1. 您只能捕获局部变量,而不是对象的成员变量。

4. Сonversions

4. 转换

4.1 !! Lambda is not a function pointer and it is not an anonymous function, but capture-lesslambdas can be implicitly converted to a function pointer.

4.1 !! Lambda 不是函数指针,也不是匿名函数,但无捕获的lambda 可以隐式转换为函数指针。

p.s.

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 Expressions, p.88

  2. In C++14 the extra feature which has named as "init capture" have been added. 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);};
    
  1. 有关 lambda 语法信息的更多信息,请参见编程语言 C++ 工作草案 #337, 2012-01-16, 5.1.2。Lambda 表达式,第 88 页

  2. 在 C++14 中,添加了名为“init capture”的额外功能。它允许任意声明闭包数据成员:

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

回答by Ted

A lambda function is an anonymous function that you create in-line. It can capture variables as some have explained, (e.g. http://www.stroustrup.com/C++11FAQ.html#lambda) but there are some limitations. For example, if there's a callback interface like this,

lambda 函数是您在线创建的匿名函数。正如某些人所解释的,它可以捕获变量(例如http://www.stroustrup.com/C++11FAQ.html#lambda),但有一些限制。例如,如果有这样的回调接口,

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:

您可以在现场编写一个函数来使用它,就像下面传递给 apply 的函数一样:

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. If you want to use captures, you have to rely on the library and

由于 C++11 标准的限制。如果要使用捕获,则必须依赖库和

#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');
    });
}

回答by gbk

One of the best explanation of lambda expressionis given from author of C++ Bjarne Stroustrupin his book ***The C++ Programming Language***chapter 11 (ISBN-13: 978-0321563842):

lambda expressionC++ Bjarne Stroustrup 的作者在他的书***The C++ Programming Language***第 11 章 ( ISBN-13: 978-0321563842) 中给出了最好的解释之一:

What is a lambda expression?

What is a lambda expression?

A lambda expression, sometimes also referred to as a lambdafunction or (strictly speaking incorrectly, but colloquially) as a lambda, is a simplified notation for defining and using an anonymous function object. Instead of defining a named class with an operator(), later making an object of that class, and finally invoking it, we can use a shorthand.

lambda表达式,有时也被称作拉姆达函数或(严格地说不正确,但通俗),为 的λ,是用于定义和使用的简化表示法匿名功能对象。我们可以使用简写,而不是使用 operator() 定义命名类,然后创建该类的对象,最后调用它。

When would I use one?

When would I use one?

This is particularly useful when we want to pass an operation as an argument to an algorithm. In the context of graphical user interfaces (and elsewhere), such operations are often referred to as callbacks.

当我们想要将操作作为参数传递给算法时,这特别有用。在图形用户界面(和其他地方)的上下文中,此类操作通常称为回调

What class of problem do they solve that wasn't possible prior to their introduction?

What class of problem do they solve that wasn't possible prior to their introduction?

Here i guess every action done with lambda expression can be solved without them, but with much more code and much bigger complexity. Lambda expression this is the way of optimization for your code and a way of making it more attractive. As sad by Stroustup :

在这里,我想用 lambda 表达式完成的每个动作都可以在没有它们的情况下解决,但是代码更多,复杂性更高。Lambda 表达式这是优化代码的方式,也是使其更具吸引力的方式。正如 Stroustup 悲伤的那样:

effective ways of optimizing

有效的优化方法

Some examples

Some examples

via lambda expression

通过 lambda 表达式

void print_modulo(const vector<int>& v, ostream& os, int m) // output v[i] to os if v[i]%m==0
{
    for_each(begin(v),end(v),
        [&os,m](int x) { 
           if (x%m==0) os << x << '\n';
         });
}

or via function

或通过函数

class Modulo_print {
         ostream& os; // members to hold the capture list int m;
     public:
         Modulo_print(ostream& s, int mm) :os(s), m(mm) {} 
         void operator()(int x) const
           { 
             if (x%m==0) os << x << '\n'; 
           }
};

or even

甚至

void print_modulo(const vector<int>& v, ostream& os, int m) 
     // output v[i] to os if v[i]%m==0
{
    class Modulo_print {
        ostream& os; // members to hold the capture list
        int m; 
        public:
           Modulo_print (ostream& s, int mm) :os(s), m(mm) {}
           void operator()(int x) const
           { 
               if (x%m==0) os << x << '\n';
           }
     };
     for_each(begin(v),end(v),Modulo_print{os,m}); 
}

if u need u can name lambda expressionlike below:

如果你需要你可以命名lambda expression如下:

void print_modulo(const vector<int>& v, ostream& os, int m)
    // output v[i] to os if v[i]%m==0
{
      auto Modulo_print = [&os,m] (int x) { if (x%m==0) os << x << '\n'; };
      for_each(begin(v),end(v),Modulo_print);
 }

Or assume another simple sample

或者假设另一个简单的样本

void TestFunctions::simpleLambda() {
    bool sensitive = true;
    std::vector<int> v = std::vector<int>({1,33,3,4,5,6,7});

    sort(v.begin(),v.end(),
         [sensitive](int x, int y) {
             printf("\n%i\n",  x < y);
             return sensitive ? x < y : abs(x) < abs(y);
         });


    printf("sorted");
    for_each(v.begin(), v.end(),
             [](int x) {
                 printf("x - %i;", x);
             }
             );
}

will generate next

将生成下一个

0

1

0

1

0

1

0

1

0

1

0 sortedx - 1;x - 3;x - 4;x - 5;x - 6;x - 7;x - 33;

0

1

0

1

0

1

0

1

0

1

0 排序x - 1;x - 3;x - 4;x - 5;x - 6;x - 7;x - 33;

[]- this is capture list or lambda introducer: if lambdasrequire no access to their local environment we can use it.

[]- 这是捕获列表或lambda introducer:如果lambdas不需要访问他们的本地环境,我们可以使用它。

Quote from book:

引自书中:

The first character of a lambda expression is always [. A lambda introducer can take various forms:

? []: an empty capture list. This implies that no local names from the surrounding context can be used in the lambda body. For such lambda expressions, data is obtained from arguments or from nonlocal variables.

? [&]: implicitly capture by reference. All local names can be used. All local variables are accessed by reference.

? [=]: implicitly capture by value. All local names can be used. All names refer to copies of the local variables taken at the point of call of the lambda expression.

? [capture-list]:explicit capture; the capture-list is the list of names of local variables to be captured (i.e., stored in the object) by reference or by value. Variables with names preceded by & are captured by reference. Other variables are captured by value. A capture list can also contain this and names followed by ... as elements.

? [&, capture-list]: implicitly capture by reference all local variables with names not men- tioned in the list. The capture list can contain this. Listed names cannot be preceded by &. Variables named in the capture list are captured by value.

? [=, capture-list]: implicitly capture by value all local variables with names not mentioned in the list. The capture list cannot contain this. The listed names must be preceded by &. Vari- ables named in the capture list are captured by reference.

Note that a local name preceded by & is always captured by reference and a local name not pre- ceded by & is always captured by value. Only capture by reference allows modification of variables in the calling environment.

lambda 表达式的第一个字符始终是[。lambda 引入器可以采用多种形式:

? []:一个空的捕获列表。这意味着不能在 lambda 主体中使用来自周围上下文的本地名称。对于此类 lambda 表达式,数据是从参数或非局部变量中获取的。

? [&]:通过引用隐式捕获。可以使用所有本地名称。所有局部变量都通过引用访问。

? [=]: 按值隐式捕获。可以使用所有本地名称。所有名称都是指在调用 lambda 表达式时获取的局部变量的副本。

? [捕获列表]:显式捕获;捕获列表是要通过引用或值捕获(即存储在对象中)的局部变量的名称列表。名称以 & 开头的变量通过引用捕获。其他变量按值捕获。捕获列表还可以包含 this 和名称后跟 ... 作为元素。

? [&, capture-list]:通过引用隐式捕获所有名称未在列表中提及的局部变量。捕获列表可以包含这个。列出的名称不能以 & 开头。捕获列表中命名的变量按值捕获。

? [=, capture-list]:按值隐式捕获列表中未提及名称的所有局部变量。捕获列表不能包含此内容。列出的名称必须以 & 开头。捕获列表中命名的变量是通过引用捕获的。

请注意,以 & 开头的本地名称始终通过引用捕获,而未以 & 开头的本地名称始终通过值捕获。只有通过引用捕获才允许修改调用环境中的变量。

Additional

Additional

Lambda expressionformat

Lambda expression格式

enter image description here

在此处输入图片说明

Additional references:

补充参考:

回答by Sachin Nale

The lambda's in c++ are treated as "on the go available function". yes its literally on the go, you define it; use it; and as the parent function scope finishes the lambda function is gone.

C++ 中的 lambda 被视为“随时可用的函数”。是的,它确实在旅途中,您可以定义它;用它; 并且随着父函数作用域完成,lambda 函数消失了。

c++ introduced it in c++ 11 and everyone started using it like at every possible place. the example and what is lambda can be find here https://en.cppreference.com/w/cpp/language/lambda

c++ 在 c++ 11 中引入了它,每个人都开始在任何可能的地方使用它。示例以及什么是 lambda 可以在这里找到https://en.cppreference.com/w/cpp/language/lambda

i will describe which is not there but essential to know for every c++ programmer

我将描述哪些不是每个 C++ 程序员都必须知道的

Lambda is not meant to use everywhere and every function cannot be replaced with lambda. It's also not the fastest one compare to normal function. because it has some overhead which need to be handled by lambda.

Lambda 并不意味着在任何地方都可以使用,并且每个函数都不能用 lambda 替换。与正常功能相比,它也不是最快的。因为它有一些开销需要由 lambda 处理。

it will surely help in reducing number of lines in some cases. it can be basically used for the section of code, which is getting called in same function one or more time and that piece of code is not needed anywhere else so that you can create standalone function for it.

在某些情况下,它肯定有助于减少行数。它基本上可以用于在同一函数中被调用一次或多次的代码段,并且该段代码在其他任何地方都不需要,因此您可以为其创建独立函数。

Below is the basic example of lambda and what happens in background.

下面是 lambda 的基本示例以及在后台发生的事情。

User code:

用户代码:

int main()
{
  // Lambda & auto
  int member=10;
  auto endGame = [=](int a, int b){ return a+b+member;};

  endGame(4,5);

  return 0;

}

How compile expands it:

compile 如何扩展它:

int main()
{
  int member = 10;

  class __lambda_6_18
  {
    int member;
    public: 
    inline /*constexpr */ int operator()(int a, int b) const
    {
      return a + b + member;
    }

    public: __lambda_6_18(int _member)
    : member{_member}
    {}

  };

  __lambda_6_18 endGame = __lambda_6_18{member};
  endGame.operator()(4, 5);

  return 0;
}

so as you can see, what kind of overhead it adds when you use it. so its not good idea to use them everywhere. it can be used at places where they are applicable.

如您所见,使用它时会增加什么样的开销。所以在任何地方使用它们并不是一个好主意。它可以在它们适用的地方使用。

回答by Misgevolution

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 bsizecases. 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,您可能需要针对不同的bsize情况做一些事情。当然你可以创建一个函数,但是如果你想限制在灵魂用户函数范围内的使用呢?lambda 的性质满足了这个要求,我在这种情况下使用它。

回答by sergiol

One problem it solves: Code simpler than lambda for a call in constructor that uses an output parameter function for initializing a const member

它解决的一个问题:在构造函数中调用比 lambda 更简单的代码,该构造函数使用输出参数函数来初始化 const 成员

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 成员,该函数通过将其输出作为输出参数返回来设置其值。