18

可能重复:
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>'

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

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

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

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

4

3 回答 3

15

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

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

允许您的用例将意味着您需要在代码中提前扫描的另一种情况,因为要确定 in 的类型,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类型。

于 2011-10-22T18:04:17.810 回答
6

在我看来,auto a案例和std::function<void()> a案例之间的重要区别在于类型std::function<void()>不知道/不关心它所指的实际函数的类型到底是什么。写作:

std::function<void()> a;

非常好,其中:

auto a;

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

于 2011-10-22T18:15:53.483 回答
2

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

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

于 2011-10-22T18:22:49.187 回答