我正在观看一个名为 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
在创建闭包后立即释放)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/