【问题标题】:Lambda <-> closure equivalence in C++C++ 中的 Lambda <-> 闭包等价
【发布时间】:2020-09-01 20:28:49
【问题描述】:

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

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

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

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

我尝试在 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++ 中有一种可行的方法吗?

【问题讨论】:

  • 您的程序可以编译,但实际上并不能运行并打印出正确的结果。
  • @cigien 你是对的。我需要对此进行调查
  • @cigien:我更新了问题是为了说明代码实际上是错误的

标签: c++ lambda closures


【解决方案1】:

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

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

lambda 表达式的类型(也是闭包对象的类型)是唯一的、未命名的非联合类类型,称为闭包类型,其属性如下所述。

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

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

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-06-28
    • 2023-03-09
    • 2014-04-15
    • 1970-01-01
    • 1970-01-01
    • 2010-11-03
    • 2023-04-06
    相关资源
    最近更新 更多