为何带推导返回类型的递归Lambda无法正常工作?
为何带推导返回类型的递归Lambda无法正常工作?
咱们先把你的问题代码和编译错误摆出来,方便搞清楚来龙去脉:
你的代码是这样的:
int main() { auto fn = []<typename T>(this auto&& self, T n) { if (n > 0) { self(n - 1); } }; fn(3); }
用clang-20 -std=c++23编译时,会弹出这个错误:
<source>:4:13: error: function 'operator()<int, (lambda at <source>:2:15) &>' with deduced return type cannot be used before it is defined 4 | self(n - 1); | ^
问题到底出在哪?
其实这是个典型的「顺序矛盾」问题:Lambda的调用运算符operator()默认是推导返回类型(因为你没写-> 返回类型),而C++编译器推导返回类型的逻辑是:必须把函数体完整扫一遍,才能确定最终的返回值类型。
但递归调用直接打破了这个顺序——编译器刚要着手推导返回类型,就看到你调用了self(n-1),也就是调用了这个Lambda自己的operator()。可这时候这个operator()的返回类型还没推导完呢,相当于编译器手里只有个半成品的函数,你就让它用这个半成品干活,它当然会懵,直接报错说「你用这个函数的时候我还没把它定义好呢」。
怎么解决这个问题?
最直接的办法就是显式指定返回类型,提前给编译器吃一颗定心丸:
int main() { auto fn = []<typename T>(this auto&& self, T n) -> void { if (n > 0) { self(n - 1); } }; fn(3); }
这里我们明确写了-> void,编译器一开始就知道这个Lambda的调用运算符返回void,递归调用的时候,它已经拿到了完整的函数签名,自然就能正常处理了。
如果你的递归Lambda是有返回值的(比如计算阶乘),同样的道理,只要显式写出返回类型(或者用decltype(auto)结合能提前推导的表达式),就能解决这个矛盾。
内容来源于stack exchange
相关产品推荐
相关产品推荐

