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

时间:2011-10-22 17:56:08

标签: c++ lambda c++11 type-inference auto

  

可能重复:
  Recursive lambda functions in c++0x

如果我把它写成:

,为什么我不能递归地调用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版本无法编译的原因。

3 个答案:

答案 0 :(得分:15)

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

此类特殊情况容易出错和误用。当您提出类似a()之类的内容应该有效时,您需要定义规则。 operator()如何查找? a类型的准确状态是什么?这种类型会完整吗? (这意味着你已经知道了lambda的捕获列表)。一旦你以符合规范的格式制定了它,就可以更容易地对其进行陈述。

允许您的用例意味着您需要在代码中向前扫描的另一种情况,因为要确定aa()的类型,您必须确保初始化程序没有任何结果“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 类型。

答案 1 :(得分:6)

我认为auto a案例和std::function<void()> a案例之间的重要区别在于std::function<void()>类型不知道/关心真实函数的类型是什么指的确是。写作:

std::function<void()> a;

非常好,其中:

auto a;

没什么意义。因此,如果您使用std::function<void()>来合成捕获的时间,那么所有需要了解的类型都是已知的,而auto则尚未知道。

答案 2 :(得分:2)

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

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