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();
};
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
不是类型。它只是代表待推断类型的类型说明符。因此,表达式永远不能具有自动类型。