lambda 中的递归调用 (C++11)

发布于 2024-12-11 18:45:19 字数 1551 浏览 3 评论 0原文

可能的重复:
c++0x 中的递归 lambda 函数

为什么我不能递归调用 lambda 如果我将其写为:

auto a = [&]
{ 
   static int i = 0; i++;
   std::cout << i << std::endl; 
   if (i<10) 
     a(); //recursive call
};

它给出编译错误(ideone):

prog.cpp:8:18: error: '((const main()::<lambda()>*)this)->main()::<lambda()>::a' cannot be used as a function

prog.cpp: In function 'int main()':
prog.cpp:9:9: error: variable 'auto a' with 'auto' type used in its own initializer

什么错误是什么意思?

我明白我不能写这个的原因:

auto i=i+1; //error: unable to deduce 'auto' from '<expression error>'

我们不能写这个,因为 i 的类型必须从它的初始化中推断出来,这意味着如果 i 则无法推断出类型 本身出现在初始化中 (ideone)。但对于 lambda 来说这有什么关系呢?如果我没记错的话,lambda 的类型是由它的参数和返回类型决定的;如果它不返回任何内容,则它不依赖于主体(在这种情况下,返回类型将被推导为 void,无论 lambda 主体中的其他语句如何)。

无论如何,我有一个解决方法,我可以使用 std::function 代替:

std::function<void()> a = [&] 
{ 
   static int i = 0; i++;
   std::cout << i << std::endl; 
   if (i<10) 
      a();
};

编译罚款 (ideone)。但我仍然有兴趣知道 auto 版本无法编译的原因。

Possible Duplicate:
Recursive lambda functions in c++0x

Why can't I call a lambda recursively if I write it as:

auto a = [&]
{ 
   static int i = 0; i++;
   std::cout << i << std::endl; 
   if (i<10) 
     a(); //recursive call
};

It gives compilation error (ideone):

prog.cpp:8:18: error: '((const main()::<lambda()>*)this)->main()::<lambda()>::a' cannot be used as a function

prog.cpp: In function 'int main()':
prog.cpp:9:9: error: variable 'auto a' with 'auto' type used in its own initializer

What does the error mean?

I understand the reason why I can't write this:

auto i=i+1; //error: unable to deduce 'auto' from '<expression error>'

We can't write this because the type of i has to be deduced from it's initialization, which means the type cannot be deduced if i itself appears in the initialization (ideone). But how does it matter in case of lambda? If I'm not wrong, the type of a lambda is determined by it's parameter(s) and the return type; it doesn't depend on the body if it returns nothing (in which case, the return type is deduced as void, irrespective of other statements in the lambda-body).

Anyway, I got a workaround, and I can use std::function instead as:

std::function<void()> a = [&] 
{ 
   static int i = 0; i++;
   std::cout << i << std::endl; 
   if (i<10) 
      a();
};

which compile fines (ideone). But I'm still interested to know the reason why the auto version doesn't compile.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

极度宠爱 2024-12-18 18:45:19

原因是 auto 变量的 lambda 表达式初始值设定项没有特殊情况。

这种特殊情况很容易出现错误和误用。当您建议像 a() 这样的东西应该起作用时,您需要定义规则。 operator() 是如何查找的? a 类型的精确状态是什么?类型会完整吗? (这意味着您已经知道 lambda 的捕获列表)。一旦您以适合规范的合理格式制定了该内容,就可以更轻松地对其进行陈述。

允许您的用例意味着您需要在代码中提前扫描的另一种情况,因为要确定 a() 中的 a 的类型,您必须确保初始化程序没有任何可以“unlambda”类型的内容结束

struct y { void operator()() { } };
template<typename T> y operator+(T, y) { return y(); }
auto x = [] { x(); } + y();

。在这种情况下,x() 将调用 y::operator(),而不是 lambda。

现在,a 被禁止在其整个初始值设定项中提及。因为在 C++ 中,auto 不是一种类型。它只是一个类型说明符,代表要推导的类型。因此,表达式永远不能具有 auto 类型。

The reason is that there is no special case for lambda-expression initializers of auto variables.

Such special cases would be prone to errors and misuses. You need to define the rules when you propose that something like a() should work. How is the operator() looked up? What is the precise state of a's type? Will the type be complete? (which implies that you already know the capture list of the lambda). Once you have formulated that in a format reasonable for a spec, it would be easier to make statements on it.

Allowing your use case would mean yet another case where you need to scan ahead in code, because to determine the type of a in a() you must be sure that the initializer ends with nothing that could "unlambda" the type

struct y { void operator()() { } };
template<typename T> y operator+(T, y) { return y(); }
auto x = [] { x(); } + y();

In this case, x() would call y::operator(), not the lambda.

As it is now, a is simply forbidden to be mentioned in its entire initializer. Because in C++, auto is not a type. It is merely a type specifier standing for a to-be-deduced type. As a consequence, an expression can never have type auto.

情定在深秋 2024-12-18 18:45:19

正如我所见, auto a 情况和 std::function之间的重要区别是:一种情况是类型 std::function不知道/关心它所引用的实际函数的类型到底是什么。写作:

std::function<void()> a;

完全没问题,而 as:

auto a;

毫无意义。因此,当需要合成捕获时,如果您使用 std::function,则所有需要了解的类型都已经知道,而使用 auto代码> 目前还不知道。

As I see it the important difference between the auto a case and the std::function<void()> a case is that the type std::function<void()> doesn't know/care about what the type of the real function it refers to really is. Writing:

std::function<void()> a;

is perfectly fine, where as:

auto a;

makes little sense. So when the time comes to synthesize the capture if you use std::function<void()> all that needs to be known about the type is already known, whereas with auto it's not yet known.

夜深人未静 2024-12-18 18:45:19

在递归函数中,ff 定义,在以下情况下,f 的返回类型也由 f 确定auto 所以它会导致无限递归。

auto 尝试派生类型时。 decltype(f()) 将进一步推导出另一个 decltype(f)`,因为 f 派生为 f,例如对任何递归的调用也是递归的。当应用于递归函数时,返回类型确定会变成递归。在递归函数中,递归结束可以在运行时完成。但决定只是静态的

In a recursive function f is defined by f and return type of f is also determined by f in case of auto so it leads to infinite recursion.

when auto tries to derive a type. decltype(f()) will further deduce to another decltype(f)` as f derives to f e.g. a call on anything recursive is recursive too. return type determination turns recursive when applied on a recursive function. in a recursive function end of the recursion may be done on runtime. but determination is static only

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文