C++ 在lambda函数语法中,';捕获列表';发球?

C++ 在lambda函数语法中,';捕获列表';发球?,c++,c++11,lambda,C++,C++11,Lambda,例如,这是一个代码,用于计算std::vector: std::for_each( vector.begin(), vector.end(), [&](int n) { sum_of_elems += n; } ); 我理解lambda函数只是无名函数 我理解lambda函数语法 我不明白为什么lambda函数需要捕获列表,而普通函数不需要 捕获列表提供了哪些额外信息 为什么正常功能不需要这些信息 lambda函数不仅仅是无名函数吗 从您

例如,这是一个代码,用于计算
std::vector

std::for_each(
    vector.begin(),
    vector.end(),
    [&](int n) {
        sum_of_elems += n;
    }
);
我理解lambda函数只是无名函数

我理解lambda函数语法

我不明白为什么lambda函数需要捕获列表,而普通函数不需要

  • 捕获列表提供了哪些额外信息
  • 为什么正常功能不需要这些信息
  • lambda函数不仅仅是无名函数吗

  • 从您给出的语法链接中,捕获列表“定义lambda外部的哪些内容应该在函数体中可用以及如何使用”

    普通函数可以通过以下几种方式使用外部数据:

  • 静态场
  • 实例字段
  • 参数(包括参考参数)
  • 全球的
  • Lambda添加了在另一个函数中包含一个未命名函数的功能。然后lambda可以使用您指定的值。与普通函数不同,它可以包含外部函数的局部变量

    正如这个答案所说,您还可以指定要捕获的方式。阿伍德兰德在书中举了几个例子。例如,您可以通过引用(如引用参数)捕获一个外部变量,并通过值捕获所有其他变量:

    [=, &epsilon]
    
    编辑:

    区分签名和lambda内部使用的内容很重要。lambda的签名是参数类型的有序列表,加上返回值的类型

    例如,一元函数接受特定类型的单个值,并返回另一类型的值

    但是,在内部,它可以使用其他值。举个简单的例子:

    [x, y](int z) -> int 
    {
       return x + y - z;
    }
    
    lambda的调用者只知道它接受
    int
    并返回
    int
    。然而,在内部,它碰巧使用了另外两个变量的值

    lambda函数不仅仅是无名函数吗

    对!!除了匿名之外,它们还可以引用词汇范围内的变量。在您的例子中,一个例子是
    sum\u of_elems
    变量(我想它既不是参数也不是全局变量)。C++中的正常函数不能实现。< /P> 捕获列表提供了哪些额外信息

    捕获列表提供了

  • 要使用捕获的变量列表
  • 应如何捕获它们的信息(通过引用/通过值)
  • 在其他(如函数式)语言中,这是不必要的,因为它们总是以一种方式引用值(如,如果值是不可变的,则捕获将按值进行;另一种可能性是,所有内容都是堆上的变量,因此所有内容都由引用捕获,您不必担心其生存期等)。在C++中,必须指定它来选择引用(可以改变变量,但是当lambda超出变量时会被炸毁)和值(所有的变化都在lambda内部隔离,但只要LAMBDA生存,基本上,它将是一个代表lambda的结构中的字段)。
    您可以使用capture default符号使编译器捕获所有需要的变量,该符号仅指定默认捕获模式(在您的示例中:
    &
    =>reference;
    =
    将是value)。在这种情况下,基本上会捕获lambda中从外部作用域引用的所有变量。

    我们试图解决的基本问题是,某些算法要求函数只接受一组特定的参数(在您的示例中为一个
    int
    )。但是,我们希望函数能够操纵或检查其他对象,可能如下所示:

    void what_we_want(int n, std::set<int> const & conditions, int & total)
    {
        if (conditions.find(n) != conditions.end()) { total += n; }
    }
    
    现在我们可以用一个适当初始化的函子调用该算法:

    std::set<int> conditions;
    int total;
    
    for_each(v.begin(), v.end(), what_we_must_write(conditions, total));
    
    简写的捕获列表
    [=]
    [&]
    只捕获“所有内容”(分别通过值或引用),这意味着编译器会为您计算出具体的捕获列表(它实际上不会将所有内容都放入closure对象中,而只将您需要的内容放入其中)

    因此,简而言之:一个没有捕获的闭包对象就像一个自由函数,一个有捕获的闭包就像一个有适当定义和初始化的私有成员对象的函子对象。

    考虑一下:

    std::function<int()>
    make_generator(int const& i)
    {
        return [i] { return i; };
    }
    
    // could be used like so:
    int i = 42;
    auto g0 = make_generator(i);
    i = 121;
    auto g1 = make_generator(i);
    i = 0;
    
    assert( g0() == 42 );
    assert( g1() == 121 );
    
    std::函数
    make_发生器(内部常数和i)
    {
    return[i]{return i;};
    }
    //可以这样使用:
    int i=42;
    auto g0=制造发电机(i);
    i=121;
    自动g1=制造发电机(i);
    i=0;
    断言(g0()==42);
    断言(g1()==121);
    
    请注意,在这种情况下,创建的两个生成器都有自己的
    i
    。这是不能用普通函数重新创建的,因此这些函数不使用捕获列表。捕获列表解决一个版本的

    lambda函数不仅仅是无名函数吗

    这是一个非常聪明的问题。lambda表达式创建的对象实际上比常规函数更强大:它们是(并且标准确实将lambda表达式创建的对象称为“闭包对象”)。简单地说,闭包是一个结合了绑定范围的函数。C++语法选择了一种常见的函数形式的函数位(具有函数体的延迟返回类型的参数列表,部分是可选的),而捕获列表是指定哪个局部变量将参与绑定范围的语法(非局部变量被自动引入)。

    注意,其他具有闭包的语言通常没有与C++捕获列表类似的构造。C++由于其内存模型(本地变量只活在本地范围内)而设计了捕获列表的选择,并且它的哲学不为不使用的东西付费(如果本地变量被捕获时自动地活得更长)可能不是理想的。

    auto what_we_get = [&conditions, &total](int n) -> void {
        if (condiditons.find(n) != conditions.end()) { total += n; } };
    
    std::function<int()>
    make_generator(int const& i)
    {
        return [i] { return i; };
    }
    
    // could be used like so:
    int i = 42;
    auto g0 = make_generator(i);
    i = 121;
    auto g1 = make_generator(i);
    i = 0;
    
    assert( g0() == 42 );
    assert( g1() == 121 );