c++ - C++ 中的 Lambda <-> 闭包等价

标签 c++ lambda closures

我正在观看一个名为 Lambda? You Keep Using that Letter 的视频由 Kevlin Henney 撰写,他指出闭包和对象基本上是等价的:

然后他通过this javascript code 证明了他的观点。它将堆栈实现为闭包:

const newStack = () => {
    const items = []
    return {
        depth: () => items.lengh,
        top: () => items[0],
        push: newTop => { items.unshift(newTop) },
        pop: () => { items.shift() },
    }
}

闭包相对于类的优势在于它的状态实际上是隐藏的,而私有(private)成员比“隐藏”更“不可访问”。

我试图在 C++ 中做一些等效的事情。但是,似乎很难用 C++ 来表达这一点。

我当前的版本在那里,它有两个主要缺点:
  • 它可以编译,但不会工作(内部 shared_ptr 在创建闭包后立即释放)
  • 有点冗长:depth、top、push 和 pop 重复了 3 次。

  • auto newStack = []() {
      auto items = std::make_shared<std::stack<int>>();
    
      auto depth = [&items]() { return items->size();};
      auto top = [&items]() { return items->top(); };
      auto push = [&items](int newTop) {  items->push(newTop); };
      auto pop = [&items]() { items->pop(); };
    
      struct R {
        decltype(depth) depth;
        decltype(top) top;
        decltype(push) push;
        decltype(pop) pop;
      };
      return R{ depth, top, push, pop};
    };
    
    

    godbolt version here

    在 C++ 中有没有可行的方法来做到这一点?

    最佳答案

    是的,当然在 C++ 中有更好的方法:不要使用 lambda。

    一个 lambda 表达式定义一个类。闭包是该类的一个实例——一个对象。我们不需要与其他语言进行比较来告诉我们——这正是 C++ 中定义 lambda 和闭包的方式。 §[expr.prim.lambda.closure]:

    The type of a lambda-expression (which is also the type of the closure object) is a unique, unnamed non-union class type, called the closure type, whose properties are described below.



    但是(这是很重要的一点)至少在 C++ 中,lambda 表达式定义了一个具有非常有限的公共(public)接口(interface)的类。具体来说,它提供了 operator() 的重载。 ,如果它没有捕获任何东西,则转换为指向函数的指针。如果它确实捕获了某些东西,它还定义了一个构造函数来进行捕获。当然,如果它捕捉到了东西,它会定义成员变量来保存它捕捉到的任何东西。

    但这就是它真正定义的全部。并不是说它在隐藏它可能包含的任何其他内容方面做得更好。这是它真的不包含任何其他东西。

    在您的情况下,您正在尝试定义一个具有四个独立成员函数的类型,这些函数都在它们共享的某些状态下运行。正如您所展示的,将状态外部化是有可能的,因此您拥有的东西几乎等同于一些 C 代码(或按此顺序排列的东西),它只包含数据和一些对该数据进行操作的函数。是的,您可以将它们组合成一个结构,以至少对具有成员函数的类进行一些模仿。

    但是你几乎是在与系统(可以这么说)在 C++ 中做这件事。 Lambdas/closures(正如它们在 C++ 中定义的那样)并不是为了让您定义具有多个单独入口点的事物,每个入口点对共享数据执行单独的操作。正如塞缪尔·约翰逊(Samuel Johnson)的老台词所说,“[它] 就像一只用后腿走路的狗。它做得不好;但你会惊讶地发现它完全做到了。”

    关于c++ - C++ 中的 Lambda <-> 闭包等价,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61828965/

    相关文章:

    c++ - Lambda函数,段错误预防

    ruby - Ruby 中的 lambda 帮助

    node.js - 用动态/脚本语言构建松散耦合系统的设计模式

    swift - 在结构中使用静态闭包安全吗?

    javascript - 是否有可能访问与 JavaScript 中的函数实例关联的闭包中捕获的变量

    c++ - 获取可变参数模板可变参数模板参数可变参数

    c++ - 特定视频/图形适配器上的 EnumDisplayMonitors?

    c++ - 如何创建进程并让它们执行不同的分配任务,例如使用 fork 从文件读取或写入文件

    c# - 在 C# 中可以同时声明和调用 lambda 表达式吗?

    lambda - 使用 Lambda 求平均值( double 存储为字符串)