这是我在Javascript权威指南中看到的javascript闭包代码。我想把它写成C ++ 11
var uniqueID1 = (function()
{
var id = 0;
return function() { return id++; };
})();
这是我写的cpp代码。但它没有被编译。 C ++ 11可以表示相同的表达式吗?
auto c = []() -> int (*)() { int x = 0; return [&x]() -> int { return x++; }};
我正在使用VS2010
修改 这是我制作的完整javascript示例代码。您可以轻松测试代码在Web浏览器中的工作方式。
<head>
<script language="javascript">
var uniqueID1 = (function()
{
var id = 0;
return function() { return id++; };
})();
var uniqueID2 = (function()
{
var id = 0;
return function() { return id++; };
})();
</script>
</head>
<body>
<input value = "uniqueid1" type="button" OnClick="alert(uniqueID1());"></input>
<input value = "uniqueid2" type="button" OnClick="alert(uniqueID2());"></input>
</body>
</html>
答案 0 :(得分:19)
好的,首先让我们分解你的JavaScript。
function()
{
var id = 0;
return function() { return id++; };
}
这会创建一个功能。没有名称的函数,不带参数。调用此函数时,将返回一个新函数。内部函数可以访问本地范围的变量,并且该变量将成为该内部函数状态的一部分。
每次调用此函数时,它都会返回 new 函数。新函数将拥有自己的状态(毕竟,var id = 0;
必须做一些事情)。外部函数的每次调用都将返回一个具有新状态的新函数。
此:
(function()
{
var id = 0;
return function() { return id++; };
})
将函数包含在一对括号中。这是运算符优先级规则所必需的,以允许它工作:
(function()
{
var id = 0;
return function() { return id++; };
})()
这会创建一个函数,然后调用函数。这就是最后()
最后做的事情。它调用外部函数,它创建一个具有自己范围的内部函数并返回它。
在此表达式中,外部函数将丢失。没了;你不能再访问它了。你创建它的时间足够长,可以调用它,然后让它进入垃圾收集的垃圾桶。
鉴于所有这些,我们可以看到这句话:
var uniqueID1 = (function()
{
var id = 0;
return function() { return id++; };
})();
创建外部函数,调用返回新函数的函数,然后将内部函数存储在名为uniqueID1
的变量中。
如果您需要证明这是真的,请在HTML中尝试:
var uniqueMaker = function()
{
var id = 0;
return function() { return id++; };
};
var uniqueID1 = uniqueMaker();
var uniqueID2 = uniqueMaker();
您将获得与复制粘贴版本相同的答案。
如果我们希望C ++代码模仿这一点,我们需要使用适当的C ++代码执行每一步。
首先,内在的功能。在C ++中,词汇范围不存在。因此,您无法返回引用其他范围中的变量的函数。您只能从另一个范围返回具有 copy 变量的lambda。此外,除非您明确允许,否则lambdas无法修改范围。因此,内部代码必须如下所示:
int id = 0;
return [=]() mutable { return ++id; };
这一切都很好,但现在我们需要创建一个将返回这个有状态lambda函数的lambda。在C ++中,具有状态的函数与函数指针不同。由于lambda的类型是编译器定义的,因此无法输入其名称。因此,我们必须使用std::function
作为外部函数的返回类型。
[]() -> std::function<int()>
{
int x = 0;
return [=]() mutable { return x++; };
}
这会创建一个lambda函数,当调用它时,将返回一个具有自己状态的内部函数。独立于此函数的任何后续调用的状态。就像JavaScript示例一样。
现在,这还不够。请记住,您的JavaScript会创建外部函数,调用它,并仅存储 的返回值。外部函数本身被丢弃。所以我们需要模仿这个。幸运的是,这在C ++中很容易;它看起来就像JavaScript:
([]() -> std::function<int()>
{
int x = 0;
return [=]() mutable { return x++; };
})()
最后,我们将其粘贴在一个变量中:
auto uniqueID1 = ([]() -> std::function<int()>
{
int x = 0;
return [=]() mutable { return x++; };
})();
uniqueID1
的类型为std::function<int()>
。它不是外部函数的类型。外部函数只是用于创建内部范围的临时函数。
答案 1 :(得分:0)
我假设你不是要求字面翻译,而是如何在C ++中最好地表达这个构造。您的JavaScript构造在某种意义上是“伪造构造函数”,并且您的ID生成器最好用C ++中的简单类表示。然后你只创建该类的实例:
class UniqueID
{
unsigned int value;
public:
UniqueID() : value(0) { }
unsigned int operator()() { return ++value; }
};
用法:
UniqueID gen1, gen2;
some_function(gen1());
another_function(gen2());
Foo x(Blue, "Jim", gen1());
这种方法比std::function
包装器重量轻,尽管直接lambda会产生类似的数据结构(尽管你不知道它的类型名称)。如果您希望第一个ID为0,则可以将value
初始化为-1
(尽管将0保留为特殊值可能很有用)。