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

错误是什么意思?

我了解为什么我不能这样写的原因:
auto i=i+1; //error: unable to deduce 'auto' from '<expression error>'

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

无论如何,我有一个解决方法,可以将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的捕获列表)。一旦以适用于规范的格式制定了格式,就可以更容易地在其上声明。

允许您的用例意味着您需要在代码中进行预先扫描的另一种情况,因为要确定aa()的类型,您必须确保初始化程序以没有可能“解包”该类型的结尾

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

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

就像现在一样,a完全禁止在其整个初始化程序中提及。因为在C++中,auto不是类型。它只是代表待推断类型的类型说明符。因此,表达式永远不能具有自动类型。

07-28 01:34
查看更多