什么是lambda表达式,我什么时候应该使用?

发布于 2025-02-06 10:45:13 字数 77 浏览 2 评论 0 原文

C ++ 11中的lambda表达式是什么?我什么时候使用?他们在引入之前无法解决哪种类别的问题?

一些示例和用例将很有用。

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?

A few examples, and use cases would be useful.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(11

酷炫老祖宗 2025-02-13 10:45:14

C ++中的lambda被视为“可用功能上”。
是的,从字面上看,您将其定义;使用它;随着父函数范围的完成,lambda函数消失了。

C ++在C ++ 11中介绍了它,每个人都开始像每个可能的地方一样使用它。
可以在此处找到的示例,什么是lambda /cpp/language/lambda

我将描述哪个不是那里的,但对于每个C ++程序员

lambda都不意味着在任何地方使用,每个功能都不能被Lambda代替。与正常功能相比,这也不是最快的。因为它的开销需要由Lambda处理。

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

以下是Lambda的基本示例,也是背景中发生的情况。

用户代码:

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

  endGame(4,5);

  return 0;

}

编译如何扩展它:

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;
}

因此,您可以看到,使用它时会添加什么样的开销。
因此,在任何地方使用它们不是好主意。
它可以在适用的地方使用。

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++ 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

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

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.

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.

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:

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.

遇见了你 2025-02-13 10:45:14

好吧,我发现的一种实际用途是减少锅炉板代码。例如:

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);
  //... 
}

没有lambda,您可能需要为不同的 bsize 案例做些事情。当然,您可以创建一个函数,但是如果您想限制灵魂用户功能范围内的用法怎么办? Lambda的性质满足了这一要求,我将其用于这种情况。

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. 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.

忱杏 2025-02-13 10:45:14

C ++ 11引入了lambda表达式,以允许我们编写一个内联函数,该函数可用于

[ capture clause ] (parameters) -> return-type
{
   definition of method
}

lambda表达式中通常返回类型的简短代码段,由编译器本身评估,我们不需要明确指定该表达式。返回型零件可以被忽略,但是在某些复杂情况下,如条件语句中,编译器无法阐明返回类型,我们需要指定。

// C++ program to demonstrate lambda expression in C++
#include <bits/stdc++.h>
using namespace std;

// Function to print vector
void printVector(vector<int> v)
{
    // lambda expression to print vector
    for_each(v.begin(), v.end(), [](int i)
    {
        std::cout << i << " ";
    });
    cout << endl;
}

int main()
{
    vector<int> v {4, 1, 3, 5, 2, 3, 1, 7};

    printVector(v);

    // below snippet find first number greater than 4
    // find_if searches for an element for which
    // function(third argument) returns true
    vector<int>:: iterator p = find_if(v.begin(), v.end(), [](int i)
    {
        return i > 4;
    });
    cout << "First number greater than 4 is : " << *p << endl;


    // function to sort vector, lambda expression is for sorting in
    // non-decreasing order Compiler can make out return type as
    // bool, but shown here just for explanation
    sort(v.begin(), v.end(), [](const int& a, const int& b) -> bool
    {
        return a > b;
    });

    printVector(v);

    // function to count numbers greater than or equal to 5
    int count_5 = count_if(v.begin(), v.end(), [](int a)
    {
        return (a >= 5);
    });
    cout << "The number of elements greater than or equal to 5 is : "
        << count_5 << endl;

    // function for removing duplicate element (after sorting all
    // duplicate comes together)
    p = unique(v.begin(), v.end(), [](int a, int b)
    {
        return a == b;
    });

    // resizing vector to make size equal to total different number
    v.resize(distance(v.begin(), p));
    printVector(v);

    // accumulate function accumulate the container on the basis of
    // function provided as third argument
    int arr[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
    int f = accumulate(arr, arr + 10, 1, [](int i, int j)
    {
        return i * j;
    });

    cout << "Factorial of 10 is : " << f << endl;

    //   We can also access function by storing this into variable
    auto square = [](int i)
    {
        return i * i;
    };

    cout << "Square of 5 is : " << square(5) << endl;
}

输出

4 1 3 5 2 3 1 7
First number greater than 4 is : 5
7 5 4 3 3 2 1 1
The number of elements greater than or equal to 5 is : 2
7 5 4 3 2 1
Factorial of 10 is : 3628800
Square of 5 is : 25

lambda表达式可以通过从封闭范围访问变量来具有比普通函数更多的功率。我们可以通过三种方式从封闭范围中捕获外部变量:

  • 通过参考捕获
  • 捕获两者的值
  • 捕获(混合捕获)

用于捕获变量的语法:

  • [&amp;]:通过参考捕获所有外部变量
  • [=]:捕获所有外部按值[a,&amp; b]的变量
  • :按值捕获A,并引用B
    带有空捕获子句的lambda只能访问那些本地的变量。
    #include <bits/stdc++.h>
    using namespace std;
    
    int main()
    {
        vector<int> v1 = {3, 1, 7, 9};
        vector<int> v2 = {10, 2, 7, 16, 9};
    
        // access v1 and v2 by reference
        auto pushinto = [&] (int m)
        {
            v1.push_back(m);
            v2.push_back(m);
        };
    
        // it pushes 20 in both v1 and v2
        pushinto(20);
    
        // access v1 by copy
        [v1]()
        {
            for (auto p = v1.begin(); p != v1.end(); p++)
            {
                cout << *p << " ";
            }
        };
    
        int N = 5;
    
        // below snippet find first number greater than N
        // [N] denotes, can access only N by value
        vector<int>:: iterator p = find_if(v1.begin(), v1.end(), [N](int i)
        {
            return i > N;
        });
    
        cout << "First number greater than 5 is : " << *p << endl;
    
        // function to count numbers greater than or equal to N
        // [=] denotes, can access all variable
        int count_N = count_if(v1.begin(), v1.end(), [=](int a)
        {
            return (a >= N);
        });
    
        cout << "The number of elements greater than or equal to 5 is : "
            << count_N << endl;
    }

输出:

   First number greater than 5 is : 7
   The number of elements greater than or equal to 5 is : 3

C++ 11 introduced lambda expression to allow us write an inline function which can be used for short snippets of code

[ capture clause ] (parameters) -> return-type
{
   definition of method
}

Generally return-type in lambda expression are evaluated by compiler itself and we don’t need to specify that explicitly and -> return-type part can be ignored but in some complex case as in conditional statement, compiler can’t make out the return type and we need to specify that.

// C++ program to demonstrate lambda expression in C++
#include <bits/stdc++.h>
using namespace std;

// Function to print vector
void printVector(vector<int> v)
{
    // lambda expression to print vector
    for_each(v.begin(), v.end(), [](int i)
    {
        std::cout << i << " ";
    });
    cout << endl;
}

int main()
{
    vector<int> v {4, 1, 3, 5, 2, 3, 1, 7};

    printVector(v);

    // below snippet find first number greater than 4
    // find_if searches for an element for which
    // function(third argument) returns true
    vector<int>:: iterator p = find_if(v.begin(), v.end(), [](int i)
    {
        return i > 4;
    });
    cout << "First number greater than 4 is : " << *p << endl;


    // function to sort vector, lambda expression is for sorting in
    // non-decreasing order Compiler can make out return type as
    // bool, but shown here just for explanation
    sort(v.begin(), v.end(), [](const int& a, const int& b) -> bool
    {
        return a > b;
    });

    printVector(v);

    // function to count numbers greater than or equal to 5
    int count_5 = count_if(v.begin(), v.end(), [](int a)
    {
        return (a >= 5);
    });
    cout << "The number of elements greater than or equal to 5 is : "
        << count_5 << endl;

    // function for removing duplicate element (after sorting all
    // duplicate comes together)
    p = unique(v.begin(), v.end(), [](int a, int b)
    {
        return a == b;
    });

    // resizing vector to make size equal to total different number
    v.resize(distance(v.begin(), p));
    printVector(v);

    // accumulate function accumulate the container on the basis of
    // function provided as third argument
    int arr[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
    int f = accumulate(arr, arr + 10, 1, [](int i, int j)
    {
        return i * j;
    });

    cout << "Factorial of 10 is : " << f << endl;

    //   We can also access function by storing this into variable
    auto square = [](int i)
    {
        return i * i;
    };

    cout << "Square of 5 is : " << square(5) << endl;
}

Output

4 1 3 5 2 3 1 7
First number greater than 4 is : 5
7 5 4 3 3 2 1 1
The number of elements greater than or equal to 5 is : 2
7 5 4 3 2 1
Factorial of 10 is : 3628800
Square of 5 is : 25

A lambda expression can have more power than an ordinary function by having access to variables from the enclosing scope. We can capture external variables from enclosing scope by three ways :

  • Capture by reference
  • Capture by value
  • Capture by both (mixed capture)

The syntax used for capturing variables :

  • [&] : capture all external variable by reference
  • [=] : capture all external variable by value
  • [a, &b] : capture a by value and b by reference
    A lambda with empty capture clause [ ] can access only those variable which are local to it.
    #include <bits/stdc++.h>
    using namespace std;
    
    int main()
    {
        vector<int> v1 = {3, 1, 7, 9};
        vector<int> v2 = {10, 2, 7, 16, 9};
    
        // access v1 and v2 by reference
        auto pushinto = [&] (int m)
        {
            v1.push_back(m);
            v2.push_back(m);
        };
    
        // it pushes 20 in both v1 and v2
        pushinto(20);
    
        // access v1 by copy
        [v1]()
        {
            for (auto p = v1.begin(); p != v1.end(); p++)
            {
                cout << *p << " ";
            }
        };
    
        int N = 5;
    
        // below snippet find first number greater than N
        // [N] denotes, can access only N by value
        vector<int>:: iterator p = find_if(v1.begin(), v1.end(), [N](int i)
        {
            return i > N;
        });
    
        cout << "First number greater than 5 is : " << *p << endl;
    
        // function to count numbers greater than or equal to N
        // [=] denotes, can access all variable
        int count_N = count_if(v1.begin(), v1.end(), [=](int a)
        {
            return (a >= N);
        });
    
        cout << "The number of elements greater than or equal to 5 is : "
            << count_N << endl;
    }

Output:

   First number greater than 5 is : 7
   The number of elements greater than or equal to 5 is : 3
删除→记忆 2025-02-13 10:45:14

之前(及时)给出的答案仍然缺少对初学者的清晰度。尤其是因为可以定义/调用lambda的不同形式。好吧,也许另一个初学者的答案(没有“知识的诅咒”)可能有助于阐明这些不同的形式。

#include <iostream>
int main()
{
    //                              lambda| arguments  | |   body      ||invoc.|
    printf("direct lamda call: %d\n",  [] (int x, int y) {return x + y;} (4, 5) );
    // it is important to be aware that a lambda with invocation arguments
    // or () if no arguments are defined, can be inserted anywhere where a
    // value (whatever type) is expected

    // assignment (instead of "auto", one could also write "int"):
    auto retval = [] (int x, int y) {return x + y;}(5, 5);
    printf("the same, via variable: %d\n", retval);
    // now the same, without supplying actual arguments (definition only):
    auto funct  = [] (int x, int y) {return x + y;};
    printf("function address: %x\n", funct);
    printf("via named lambda invocation: %d\n", funct(6, 5) );
    // in this case (definition only), the lambda can be handed over to another
    // function as well, e.g.
}

输出:(

$ g++ lambda.cpp && ./a.out
direct lamda call: 9
the same, via variable: 10
function address: 4878deb0
via named lambda invocation: 11

灵感通过

要解决问题海报的其他问题,显示了一个演示数据,其中数据与lambda一起用作数据处理器函数中的函数参数àlamap():

#include <iostream>
#include <vector>
using namespace std;
template<typename Function>
void mymap(vector<int> a, Function fn) {
    for (auto &i : a) {
        printf("%d>%d  ", i, fn(a[i-1]));
    }
    printf("\n");
}
int main()
{
    vector<int> data{1,2,3,4,5};
    //   |what|       how              |
    mymap(data, [=](int x){return x*x;});
}

输出:

$ g++ lambda.cpp && ./a.out
1>1  2>4  3>9  4>16  5>25  

有关的更多信息:可以从Stack Overflow的一个创始人(2006)中找到这种减少代码重复的典型用例:

顺便说一句:您可以想到lambda表达式,就好像我们在函数中定义了正常的(数学)表达式,在该函数中可以从另一个函数中使用这些表达式(计算)。 Lambda有效地允许这一点甚至更多。

Lambdas和其他技术还有助于减少执行代码更改后的git差异“大小”。引用马丁·克拉科尔(Martin Cracauer)的

最后但并非最不重要的一点,也有差异效率。什么
哎呀,是“差异效率”吗?这意味着,如果您查看git差异
您的代码与代码的不同状态,然后您只看到
实际功能更改。没有很多样板。不多的副本
并粘贴了该功能变化的轻微变体。

(我知道文章的标题不是关于Lambdas的,而是在文章的中心附近,可以找到一些有用的说明)

The answers given before (in time) are still missing some clarity for the beginner. Especially because of the different forms that a lambda can be defined/invoked. Well, perhaps an answer from another beginner (no 'curse of knowledge') may help clarify these different forms.

#include <iostream>
int main()
{
    //                              lambda| arguments  | |   body      ||invoc.|
    printf("direct lamda call: %d\n",  [] (int x, int y) {return x + y;} (4, 5) );
    // it is important to be aware that a lambda with invocation arguments
    // or () if no arguments are defined, can be inserted anywhere where a
    // value (whatever type) is expected

    // assignment (instead of "auto", one could also write "int"):
    auto retval = [] (int x, int y) {return x + y;}(5, 5);
    printf("the same, via variable: %d\n", retval);
    // now the same, without supplying actual arguments (definition only):
    auto funct  = [] (int x, int y) {return x + y;};
    printf("function address: %x\n", funct);
    printf("via named lambda invocation: %d\n", funct(6, 5) );
    // in this case (definition only), the lambda can be handed over to another
    // function as well, e.g.
}

Output:

$ g++ lambda.cpp && ./a.out
direct lamda call: 9
the same, via variable: 10
function address: 4878deb0
via named lambda invocation: 11

(inspiration got via https://dotnettutorials.net/lesson/lambda-expressions-in-cpp/)

To address the further questions of the question poster, a demonstration is shown where data is used together with lambda as function arguments in a data processor function à la map():

#include <iostream>
#include <vector>
using namespace std;
template<typename Function>
void mymap(vector<int> a, Function fn) {
    for (auto &i : a) {
        printf("%d>%d  ", i, fn(a[i-1]));
    }
    printf("\n");
}
int main()
{
    vector<int> data{1,2,3,4,5};
    //   |what|       how              |
    mymap(data, [=](int x){return x*x;});
}

Output:

$ g++ lambda.cpp && ./a.out
1>1  2>4  3>9  4>16  5>25  

More information about this typical use case to reduce code repetitions can be found here from one of the founders of stack overflow (2006):
https://www.joelonsoftware.com/2006/08/01/can-your-programming-language-do-this/.
BTW: you could think of a lambda expression as if we had normal (mathematical) expressions defined in a function, where these can be used (computed) from within another function. The lambda effectively allows this and even more.

Lambdas and other techniques also help reduce git diff 'size' upon doing code changes. To quote Martin Cracauer in his introduction to Compile Time Computing:

Last but certainly not least, there is also Diff Efficiency. What the
heck is “diff efficiency”? It means that if you look at a git diff of
your code versus a different state of your code, then you only see the
actual functional change. Not a lot of boilerplate. Not a lot of copy
and pasted slight variants of that functional change.

(I know that the title of the article is not about lambdas, but around the center of the article, some general useful notes can be found)

满地尘埃落定 2025-02-13 10:45:14

它解决的一个问题是:代码比lambda更简单,对于使用输出参数函数来初始化const成员

您可以初始化类中的const成员,并通过回馈其输出来设置其值作为输出参数。

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

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.

红ご颜醉 2025-02-13 10:45:13

问题

C ++包含有用的通用功能,例如 std :: for_each std :: transform ,这可能非常方便。不幸的是,它们也可能很麻烦,尤其是 fuctor 您想适用是特定功能唯一的。

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

如果您仅在那个特定的地方使用 f ,那么写整个班级只是为了做一些微不足道的事情,一个人似乎过于杀伤。

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

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

但是不允许使用 f 不能传递给a 模板 c ++ 03中的功能。

新的解决方案

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

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

lambda函数只是匿名函数的句法糖。

返回类型

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

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

但是,当您开始编写更复杂的lambdas时,您会迅速遇到编译器无法推导返回类型的情况,例如:

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

要解决此问题,允许使用 - &gt;允许明确指定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;
            }
        });
}

“捕获”变量

到目前为止,除了传递给其中lambda的东西以外,我们还没有使用任何其他内容,但是我们也可以在lambda内使用其他变量。如果要访问其他变量,则可以使用捕获子句(表达式的 [] ),该示例中尚未使用,例如:

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

您可以同时通过参考和值捕获,您可以分别使用&amp; = 分别指定:

  • [&amp; epsilon,zeta] 通过参考捕获Epsilon,并通过Value
  • 捕获Epsilon [&amp;] 通过参考 [=] 捕获lambda中使用的
  • 变量
  • 所有 lambda中使用的所有变量通过参考中使用,但按值
  • [=,&amp; epsilon] 捕获Epsilon 捕获lambda中使用的所有变量,但通过引用引用的

operator() operator()< /code> IS const 默认情况下,默认情况下访问它们时,捕获将为 const 的暗示。这具有相同输入的每个调用都会产生相同结果的效果,但是您可以将lambda标记为 Mutable 请求所产生的 operator()不是<代码> const

The problem

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

#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 f once and in that specific place it seems overkill to be writing a whole class just to do something trivial and one off.

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

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, f cannot be passed to a template function in 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:

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.

Return types

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

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.:

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:

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.:

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, zeta] captures epsilon by reference and zeta by value
  • [&] captures all variables used in the lambda by reference
  • [=] captures all variables used in the lambda by value
  • [&, epsilon] captures all variables used in the lambda by reference but captures epsilon by value
  • [=, &epsilon] captures all variables used in the lambda by value but captures epsilon by reference

The generated operator() is const by default, with the implication that captures will be const when 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 mutable to request that the operator() that is produced is not const.

一城柳絮吹成雪 2025-02-13 10:45:13

什么是lambda表达?

lambda表达式的C ++概念源自lambda演算和功能编程。
lambda是一个未命名的函数(在实际编程中,而不是理论中),对于不可重复使用且不值得命名的代码短图。

在C ++中,最小lambda表达式看起来像:

[]{} // lambda with no parameters that does nothing 

[] 是捕获列表和 {} 函数正文。

lambda-expression 的完整语法包括属性, noexcept / throw - 规范,需要clauses等更为复杂。

捕获列表

捕获列表定义了从lambda的外部进行功能内部的内容以及如何可用。
它可以是:

  1. 一个值: [x]
  2. 参考 [&amp; x]
  3. 当前在范围中通过参考 [&amp;] 当前中的任何变量
  4. 与3相同,但按值 [=]
  5. 捕获 this ,并在lambda [this] 中使成员函数可召唤

您可以混合以上在逗号分隔列表中 [x,&amp; y]

init-captures(C ++ 14)

现在可以使用 = 来初始化捕获列表的元素,该元素称为 init-capture
这允许重命名变量并通过移动捕获。从标准中获取的一个示例:

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.

一个从Wikipedia中获取的示例,显示了如何使用 std :: Move

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

模板参数(C ++ 20)

自C ++ 20以来,Lambda表达式可以具有a < -parameter-list

[]<int N>() {};

a href =“ https://eel.is/c++draft/temp.pre#nt:template-parameter-list” rel =“ noreferrer”> template =“ https://eel.is/c++draft/expr.prim.lambda.general#def:generic_lambda” rel =“ noreferrer”>通用lambda /code>带有呼叫操作员模板:

struct __lambda {
    template <int N> void operator()() const {}
};

参数列表

“ noreferrer”> parameter -declaration-clause 与任何其他C ++函数相同。
当没有参数时,它可以完全省略,这意味着 [](){} 等效于 [] {] {}

通用lambdas(c ++ 14)

lambdas带有 auto 参数为通用lambda s。
auto 等于 t 在这里
t 是周围范围中某个地方某处的类型模板参数):

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

就像c ++ 20 缩写函数模板

struct __lambda {
    // C++20 equivalent
    void operator()(auto x, auto y) const { return x + y; }
    // pre-C++20 equivalent
    template <typename T, typename U>
    void operator()(T x, U y) const { return x + y; }
};

返回类型(返回类型(可能是推论)

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

还可以使用落后返回类型语法明确提供返回类型:

[](int x) -> int { return x; }

改进的返回类型扣除额(C ++ 14)

C ++ 14允许每个函数推导的返回类型,并且不将其限制为表单返回表达式的功能; 。这也扩展到兰巴斯。
默认情况下,将lambda的返回类型推定,好像其返回类型被声明为 auto

可变的lambda(C ++ 14)

如果lambda标记了可变的(例如 []()可突变{} ),则允许变异通过值捕获的值。

Mutable 表示Lambda类型的调用操作员没有 const 限定符。

功能主体

a block-statement Lambda实际上被称为。
这成为呼叫操作员的主体。

用例,

由ISO标准福利定义的库从Lambdas重大效益,并提高了几个条的可用性,因为现在用户不必在某些可访问的范围中与小型函子混乱代码。

What is a lambda expression?

The C++ concept of a lambda expression 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.

In C++, the minimal lambda expression looks like:

[]{} // lambda with no parameters that does nothing 

[] is the capture list and {} the function body.

The full syntax for a lambda-expression, including attributes, noexcept/throw-specifications, requires-clauses, etc. is more complex.

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:

  1. a value: [x]
  2. a reference [&x]
  3. any variable currently in scope by reference [&]
  4. same as 3, but by value [=]
  5. capturing this and making member functions callable within the lambda [this]

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

Init-captures (C++14)

An element of the capture list can now be initialized with =, which is called init-capture.
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:

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

The template parameters (C++20)

Since C++20, lambda expressions can have a template-parameter-list:

[]<int N>() {};

Such a generic lambda is like a non-template struct with a call operator template:

struct __lambda {
    template <int N> void operator()() const {}
};

The parameter list

The parameter-declaration-clause is the same as in any other C++ function.
It can be omitted completely when there are no parameters, meaning that [](){} is equivalent to []{}.

Generic Lambdas (C++14)

Lambdas with an auto parameter are generic lambdas.
auto would be equivalent to T here if
T were a type template argument somewhere in the surrounding scope):

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

This works just like a C++20 abbreviated function template:

struct __lambda {
    // C++20 equivalent
    void operator()(auto x, auto y) const { return x + y; }
    // pre-C++20 equivalent
    template <typename T, typename U>
    void operator()(T x, U y) const { return x + y; }
};

Return type (possibly deduced)

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

The return type can also be provided explicitly using trailing return type syntax:

[](int x) -> int { return x; }

Improved Return Type Deduction (C++14)

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.
By default, the return type of a lambda is deduced as if its return type was declared auto.

Mutable lambda (C++14)

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

mutable means that the call operator of the lambda's type does not have a const qualifier.

The function body

A block-statement will be executed when the lambda is actually called.
This becomes the body of the call operator.

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.

遗心遗梦遗幸福 2025-02-13 10:45:13

lambda表达式通常用于封装算法,以便可以传递到另一个函数。但是,可以在定义上立即执行lambda

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

在功能上等同于此

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

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

同样,您可以根据算法 ...

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

作为作为作为的一种方法来对程序进行分区的方式,您甚至可能会发现对初始化变量,您甚至可能会发现很有用将lambda表达方式作为参数传递给另一个lambda表达式...

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

lambda表达式也让您创建名为 ,这可能是避免重复逻辑的便捷方法。当将非平凡函数作为参数传递给另一个函数时,使用命名的lambdas在眼睛上(与匿名的inline lambdas相比)也往往更容易。 注意:不要忘记闭合卷曲括号后的分号。

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

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

如果随后的分析揭示了功能对象的显着初始化开销,则可以选择将其重写为正常函数。

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:

[&](){ ...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.

Similarly, you can use lambda expressions to initialize variables based on the result of an algorithm...

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...

[&]( 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.

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.

甜中书 2025-02-13 10:45:13

答案

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

答:在引擎盖下,它是具有超载 operator()const 的自动化类别的对象。这样的对象称为a 闭合,由编译器创建。
这个“闭合”概念类似于C ++ 11中的“绑定”概念,但是Lambdas通常会生成更多的性能代码。同样,通过封闭(而不是典型功能)呼叫允许完全插入。

问:我什么时候使用?

答:当您想定义“简单而又小的逻辑”并要求编译器从上一个问题中发电。您给编译器一些表达式,您想在 operator()中。所有其他内容,编译器将为您生成。

问:Lambdas在引入之前无法解决哪些类别的问题?

答:Lambdas更像是句法糖(即用于易用性的代码),例如“操作员过载”,而不必为Custom 添加全部功能,减去操作... lambdas ... lambdas将更多的不需要代码行保存,以将1-3行的真实逻辑包装到某些类等上等!一些工程师认为,如果线的数量较小,那么在其中犯错误的机会较小(我也这么认为)。

用法的示例

auto x = [=](int arg1){printf("%i", arg1); };
// Note the ending semicolon after {}.

void(*f)(int) = x;
// ^Create function pointer f that takes parameter `int`.
// ^See point 4.1 below under "Extras about Lambdas".

f(1);                // Call function f with parameter `int 1`
x(1);                // Call function x with parameter `int 1`

关于lambdas的额外功能,没有问题。如果您不感兴趣

1,请忽略本节。捕获的值。您可以捕获

1.1。您可以在lambdas中引用 static 存储持续时间的变量。他们都被俘虏了。

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

[captureVar1,captureVar2](int arg1){}
//Modification of either captured value inside the Lambda
//will *not* modify the value outside the Lambda too,
//meaning a variable outside the Lambda that is also named
//captureVar1 will be unaffected by what happens inside the Lambda.
//I.e., Variable Shadowing will occur.

1.3。您可以通过参考捕获。 &amp; - 在这种情况下,指参考,而不是指针。

   [&captureVar1,&captureVar2](int arg1){}
   //Modification of either capture value inside the Lambda
   //will modify the value outside the Lambda too!

1.4。存在表示法以按值或参考

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

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

1.5捕获所有非静态VAR。存在符号,以按值或参考捕获所有非静态var,而覆盖特定变量是特定的,要专门为副价值或副参考
示例:
按值捕获所有不静态的var,但通过参考捕获param2

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

捕获所有不静态的var,逐个参考,而通过值捕获param2

[&,Param2](int arg1){} 

2。返回类型扣除

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

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

如果lambda具有多个表达式,则必须通过尾随返回类型来指定返回类型。
同样,类似的语法可以应用于自动功能和成员功能

3。捕获的值。您无法捕获

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

4。 conversions

4.1 !! lambda不是函数指针,也不是匿名函数,但是 capture-loss lambdas可以隐式转换为函数指针。

ps

  1. 有关lambda语法信息的更多信息可以在编程语言C ++#337,2012-16,5.1.2的工作草案中找到。 lambda表达式,第88页

  2. 在C ++中14中添加了一个额外的功能,称为“初始化捕获”。它允许您任意执行关闭数据成员的声明:

      auto tofloat = [](int value){return float(value);};
    
     自动插值= [min = tofloat(0),max = tofloat(255)]
       (int值) - &gt; float
       {return(value -min) /(max -min);};
     

Answers

Q: What is a lambda expression in C++11?

A: Under the hood, it is the object of an autogenerated class with an overloaded operator() const. Such an object is called a closure and is created by the compiler.
This 'closure' concept is similar to the 'bind' concept from C++11, but lambdas typically generate more performant code. Also, calls through closures (instead of typical functions) allow full inlining.

Q: When would I use one?

A: When you want to define "simple and small logic" and ask the compiler to perform generation from previous question. You give a compiler some expressions which you want to be inside operator(). All the other stuff, the compiler will generate for you.

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

A: Lambdas are more of a syntactical sugar (i.e., code meant for ease-of-use) like "operator overloading" instead of having to make entire functions for custom add, subtract operations... Lambdas 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 lesser chance to make errors in it (I'm think so too).

Example of usage

auto x = [=](int arg1){printf("%i", arg1); };
// Note the ending semicolon after {}.

void(*f)(int) = x;
// ^Create function pointer f that takes parameter `int`.
// ^See point 4.1 below under "Extras about Lambdas".

f(1);                // Call function f with parameter `int 1`
x(1);                // Call function x with parameter `int 1`

Extras about lambdas, not covered by question. Ignore this section if you're not interested

1. Captured values. What you can capture

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

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

[captureVar1,captureVar2](int arg1){}
//Modification of either captured value inside the Lambda
//will *not* modify the value outside the Lambda too,
//meaning a variable outside the Lambda that is also named
//captureVar1 will be unaffected by what happens inside the Lambda.
//I.e., Variable Shadowing will occur.

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

   [&captureVar1,&captureVar2](int arg1){}
   //Modification of either capture value inside the Lambda
   //will modify the value outside the Lambda too!

1.4. Notation exists 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. Notation exists to capture all non-static vars by value, or by reference, while overriding specific variables to be specifically by-value or by-reference
Examples:
Capture all not-static vars by value, but by reference capture Param2

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

Capture all not-static vars by reference, but by value capture Param2

[&,Param2](int arg1){} 

2. Return type deduction

2.1. Lambda return type can be deduced if lambda is one expression. Or you can explicitly specify it.

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

If lambda has more than one expression, then return type must be specified via trailing return type.
Also, similar syntax can be applied to auto functions and member-functions

3. Captured values. What you cannot capture

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

4. Сonversions

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.

P.s.

  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 an extra feature, named as "init capture", has been added. It allows you to arbitrarily perform 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);};
    
A君 2025-02-13 10:45:13

lambda函数是您在线创建的匿名函数。它可以捕获变量,如某些人所解释的那样,(例如 http://wwwww.stroustrup.com/c+sstroustrup.com/c+++11faq11faq .html#lambda )但是有一些局限性。例如,如果有这样的回调界面,

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

则可以在现场编写一个函数,例如在下面使用的函数,

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

但是您不能这样做:

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

因为C ++ 11标准中的限制。如果要使用捕获,则必须依靠库和

#include <functional> 

(或其他某些STL库(例如算法)进行间接获取),然后使用STD ::函数,而不是将正常函数作为类似的参数传递:

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

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,

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. 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:

#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');
    });
}
┈┾☆殇 2025-02-13 10:45:13

lambda表达式的最佳解释之一是由C ++ bjarne stroustrup的作者提供的,他的书 *** *** C ++编程语言*** 第11章( isbn-13:978-0321563842

) >什么是lambda表达式?

a lambda表达式,有时也称为 lambda
功能或(严格地说不正确地说,但通俗地说)
lambda 是一种简化的符号,用于定义和使用匿名函数对象。而不是用operator()定义命名类,而是将其构成该类的对象,最后是
调用它,我们可以使用速记。

我什么时候可以使用?

当我们想通过操作作为一个
论证算法。在图形用户界面的上下文中
(和其他地方),此类操作通常称为 callbacks

他们在引入之前无法解决哪些类别的问题?

在这里我想没有lambda表达的每一个动作都可以在没有它们的情况下解决,但是还有更多代码和更大的复杂性。 lambda表达式这是对您的代码优化的方式,也是使其更具吸引力的一种方式。斯特鲁斯普(Stroustup)悲伤:

优化的有效方法

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

或通过功能

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

,即使

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

您需要的话,也可以命名 lambda表达式如下:

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

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

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

将生成下一步

0

1

0

1

0

1

0

1

0

1

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

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

书籍的报价:

lambda表达的第一个字符始终是 [。兰伯达
介绍者可以采取各种形式:

[] :一个空的捕获列表。这
暗示无法使用周围环境中的本地名称
在兰伯达的身体中。对于此类lambda表达式,数据是从
参数或非本地变量。

[&amp;] :通过
参考。所有本地名称都可以使用。所有本地变量均为
通过参考访问。

[=] :通过值隐式捕获。所有本地
可以使用名称。所有名称都涉及本地变量的副本
在lambda表达式的呼叫点。

[capture-list]:显式捕获;捕获列表是通过参考或通过值捕获的局部变量名称列表(即,存储在对象中)。名称之前的变量为&amp;被捕获
参考。其他变量按值捕获。捕获清单可以
还包含此内容,名字后面是...作为元素。

[&amp;,capture-list] :通过参考所有局部变量隐式捕获名称中未提及的所有局部变量。捕获列表可以包含此列表。列出的名称不能先于&amp;。在
捕获列表按值捕获。

[=,capture-list] :通过值模糊地捕获所有局部变量,其中列表中未提及的名称。捕获列表不能包含此列表。列出的名称必须先于&amp;。捕获列表中命名的变量是通过参考捕获的。

请注意,本地名称由&amp;总是被
参考和本地名称未由&amp;总是被
价值。仅通过参考捕获才能修改变量
呼叫环境。

附加

lambda表达式格式

“在此处输入图像说明”

附加参考:

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

What is a lambda expression?

A lambda expression, sometimes also referred to as a lambda
function 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.

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?

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 :

effective ways of optimizing

Some examples

via lambda expression

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 expression like below:

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;

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

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.

Additional

Lambda expression format

enter image description here

Additional references:

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文