如果全局函数使用非局部变量,那么它';结束了吗? 我对C++中的闭包非常困惑。我已经读过了,但是几乎所有的答案都是引用JavaScript,但是我认为C++和JavaScript之间的关闭有一些不同。因此,我发现很难将闭包的JavaScript描述与C++进行匹配。

如果全局函数使用非局部变量,那么它';结束了吗? 我对C++中的闭包非常困惑。我已经读过了,但是几乎所有的答案都是引用JavaScript,但是我认为C++和JavaScript之间的关闭有一些不同。因此,我发现很难将闭包的JavaScript描述与C++进行匹配。,c++,lambda,closures,C++,Lambda,Closures,例如,几乎所有答案都以返回函数的函数为例来演示JavaScript中的闭包。但是我在C++中没有找到类似的模式。p> 更重要的是,在JavaScript中没有所谓的“捕获列表” 我被告知,如果一个函数使用非局部变量(来自外部范围或全局范围),那么它就是一个闭包。对吗 例1: int a = 3; int am_I_a_closure(int c){ return c + a; } int main(){ } 为什么需要捕获列表?C+

例如,几乎所有答案都以返回函数的函数为例来演示JavaScript中的闭包。但是我在C++中没有找到类似的模式。p> 更重要的是,在JavaScript中没有所谓的“捕获列表”


  • 我被告知,如果一个函数使用非局部变量(来自外部范围或全局范围),那么它就是一个闭包。对吗
  • 例1:

        int a = 3;
    
        int am_I_a_closure(int c){
            return c + a;
        }
    
        int main(){
        }
    
  • 为什么需要捕获列表?C++中的lambda不能像JavaScript嵌套函数那样工作吗? 或者用另一种说法,C++中的lambda不能像全局函数访问全局(非本地)变量那样工作吗?
  • 我的意思是,通过正常的名称查找过程,如果在当前作用域中找不到名称,那么在外部作用域中找到它,然后在更多外部作用域中

    为什么需要捕获列表?为什么需要捕获外部范围变量?不能通过正常的名称查找来完成吗

    例2:

    int main(){
        int a = 3;
        {
            int b = 5;
            {
                int c = 4;
                {
                    std::cout << a+b+c <<std::endl;
                }
            }
        }
    }
    
    
    intmain(){
    INTA=3;
    {
    int b=5;
    {
    int c=4;
    {
    
    std::cout理解“闭包”很重要是一个在函数式编程中有非常特殊含义的概念。C++不是函数语言;它并不太在意严格遵守函数式编程术语。它简单地定义了各种功能,其中一些可能或可能不很好地映射到该术语。

    < javascript和C++是不同的语言。在JavaScript中,函数有一个称为“一流对象”的属性。这意味着,当您执行代码创建一个“函数”时。,您正在创建一个表示该函数的对象。包含函数的变量与包含字符串的变量、包含数组的变量或其他任何变量基本相同。您可以使用数组覆盖包含函数的变量,反之亦然

    特别是,作为一级对象的函数在创建时可以具有与其关联的状态。如果此类函数超出其作用域访问局部变量,则该作用域可以存储为函数状态的一部分;当您尝试在函数中使用该变量时,将自动访问该状态。因此,看起来您正在“走出”函数的作用域,但实际上并非如此;该作用域是随您“进入”的,您只是在访问它

    在C++中,函数不是一个第一类对象。可以获得指向函数的指针,但是函数指针与对象指针明显不同(两个之间的转换甚至不需要是有效的)。函数不是“创建的”或“被破坏的”。就C++语言而言,每一个函数总是存在,从程序开始到结束。 C++函数可以访问全局变量,但这是因为它们是全局变量。全局变量的位置在编译/链接时被烘焙到可执行文件中,因此无需与函数一起存储特殊状态即可访问它

    但是,C++确实有一个有用的概念,它可以帮助创建一个一流的函数对象的效果。即,类类型可以重载函数调用操作符<代码>操作程序()/>代码。这允许类的实例被称为函数。类实例是对象,可以具有内部状态。(又名:成员变量),而
    操作符()
    重载只是该类型的成员函数

    考虑到所有这些,您可以创建一些东西来模拟一个范围正确的函数对象。您所需要的只是一个类,该类的成员变量与它引用的函数范围之外的变量相对应。通过将外部值传递给构造函数,这些成员可以在类的构造函数中初始化。然后您有一个可以调用的有效对象,它可以使用其成员变量访问这些“外部”变量

    这是一个C++ lambda。它把所有这些都用“漂亮的、整洁的”语法包起来。它为你编写一个类;它为你写了从外部世界捕获的成员变量,并调用构造函数并传递这些变量。

    但是,C++是一种语言,它试图使你不需要比你所需要的更昂贵。你使用的外部变量越多,lambda所需要的内部成员变量越多,因此,类就越大,初始化/复制等的时间也就越长。C++(它被实现为成员变量),要求您显式地列出它(以便知道您打算捕获它)或使用默认捕获机制<代码> [[] ] /Cuth>或<代码> [&] < /Cord>(这样,您就明确放弃了对意外地使lambda类型巨大和/或慢)的抱怨。< / P> 此外,在JavaScript中,一切都是引用。变量存储对数组、函数、字典等的引用。JavaScript是一种基于引用的语言

    C++是一种面向价值的语言。JavaScript中的变量引用对象;C++中的变量是对象。C++中不能用一个对象替换另一个对象;可以复制对象的值,但仍然是对象。

    因此,lambda应该如何捕获特定变量就变得相关了。您可以通过值(将值复制到隐藏成员中)或引用(引用对象)捕获变量

    <>这是特别重要的,因为C++不是垃圾收集的
    int main(){
        std::vector<int> values = {1,5,3,4,3};
        int a = 3;
        std::find_if(values.begin(), values.end(), [](int value) {return value > a; }); //Error, `a` is not captured.
    }