[我正在观看Kevlin Henney的名为Lambda? You Keep Using that Letter的视频,他在其中指出闭包和对象在本质上是等效的:
他然后通过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};
};
在C ++中有可行的方法吗?
是的,当然,在C ++中有更好的方法:不要使用lambda。
lambda表达式定义一个类。闭包是该类的一个实例-一个对象。我们不需要与其他语言进行比较就可以告诉我们-这正是C ++中lambda和闭包的定义方式。 §[expr.prim.lambda.closure]:
lambda表达式的类型(也是闭包对象的类型)是一种唯一的,未命名的非工会类类型,称为闭包类型,其属性在下面进行描述。
但是(至少这是重要的一点)至少在C ++中,lambda表达式定义了一个very受限公共接口的类。具体来说,它提供operator()
的重载,并且如果不捕获任何内容,则转换为指向函数的指针。如果确实捕获了某些内容,它还将定义一个构造函数来进行捕获。当然,如果它捕获了事物,它会定义成员变量以保存捕获的任何事物。
但这就是它真正定义的全部。这并不是说它可以更好地隐藏它可能包含的其他内容。因为它确实不包含任何其他内容。
在您的情况下,您试图定义一个类型,该类型具有四个单独的成员函数,这些成员函数均在它们共享的某些状态下运行。正如您所展示的,可以将状态外部化,这样您就有了几乎等同于一些仅包含数据的C代码(或该顺序的某些东西)和一些对该数据进行操作的函数。是的,您可以将它们组合到一个结构中,以至少对具有成员函数的类进行一些模仿。
但是您正在与系统作斗争(可以这么说),以便在C ++中做到这一点。 Lambda /闭包(如C ++中定义的)无意让您定义具有多个单独入口点的事物,每个入口点对共享数据执行单独的操作。正如塞缪尔·约翰逊(Samuel Johnson)的老话所说:“ [它就像一条狗在后腿上行走。虽然做得不好,但是您发现它完全可以感到惊讶。”