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

Recursive call in lambda (C++11)

本文关键字:递归 调用 C++11 lambda      更新时间:2023-10-16

可能重复:
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版本没有编译的原因。

原因是auto变量的lambda表达式初始化器没有特殊情况。

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

允许您的用例将意味着您需要在代码中提前扫描的另一种情况,因为要确定a()a的类型,您必须确保初始值设定项以任何可以"解锁"类型的内容结尾

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

在我看来,auto a情况和std::function<void()> a情况之间的重要区别在于类型std::function<void()>不知道/关心它所指的实际函数的类型

std::function<void()> a;

非常好,其中为:

auto a;

毫无意义。因此,当合成捕获的时候,如果你使用std::function<void()>,所有需要知道的类型都已经知道了,而使用auto还不知道。

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

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