如果我把它写成:
,为什么我不能递归地调用lambdaauto 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
版本无法编译的原因。
答案 0 :(得分:15)
原因是auto
变量的lambda-expression初始值设定项没有特殊情况。
此类特殊情况容易出错和误用。当您提出类似a()
之类的内容应该有效时,您需要定义规则。 operator()
如何查找? a
类型的准确状态是什么?这种类型会完整吗? (这意味着你已经知道了lambda的捕获列表)。一旦你以符合规范的格式制定了它,就可以更容易地对其进行陈述。
允许您的用例意味着您需要在代码中向前扫描的另一种情况,因为要确定a
中a()
的类型,您必须确保初始化程序没有任何结果“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)
在递归函数中f
由f
定义,f
的返回类型也由f
auto
确定,因此它会导致auto
无限递归。
当{{1}}尝试派生类型时。 decltype(f())将进一步推导到另一个decltype(f)`,因为f导出f例如对任何递归的调用也是递归的。返回类型确定在应用于递归函数时变为递归。在递归函数中,递归的结束可以在运行时完成。但决定只是静态的