xin*_*aiz 13 c++ recursion lambda templates c++14
这是完整的例子:
auto callSelf = [](auto& func) {func(func);};
class wrapper : public decltype(callSelf) {
using base = decltype(callSelf);
public:
wrapper() : base(callSelf) {}
template<class T>
void operator()(T& func) {
base::operator()(func);
}
};
int main()
{
//callSelf(callSelf); // Error
wrapper w;
w(w); // OK, nice endless recursion
}
Run Code Online (Sandbox Code Playgroud)
为什么可以使用包装器,而直接执行它会导致以下错误?
main.cpp:30: error: use of '<lambda(auto:1&)> [with auto:1 = <lambda(auto:1&)>]' before deduction of 'auto'
auto callSelf = [&](auto& func) {func(func);};
~~~~^~~~~~
Run Code Online (Sandbox Code Playgroud)
Bar*_*rry 16
这实际上非常棘手.你遇到的规则是[dcl.spec.auto]:
如果需要具有未减少占位符类型的实体的类型来确定表达式的类型,则该程序是不正确的.
那就是这里出了问题:
auto callSelf = [](auto& func) {func(func);};
callSelf(callSelf);
Run Code Online (Sandbox Code Playgroud)
我们需要知道callSelf确定表达式类型的类型func(func),它是自动循环的.只需指定返回类型即可轻松解决:
auto callSelf = [](auto& func) -> void {func(func);};
callSelf(callSelf); // ok. I mean, infinite recursion, but otherwise ok. ish.
Run Code Online (Sandbox Code Playgroud)
但是,当你包装 lambda时,你会得到不同的行为.这一行在这里:
w(w);
Run Code Online (Sandbox Code Playgroud)
将一个类型的对象wrapper有效地传递给lambda.那不是它自己的类型.lambda的主体调用该对象本身,但我们知道该表达式的类型.你宣布它:
template<class T>
void operator()(T& func) {
~~~~~
Run Code Online (Sandbox Code Playgroud)
这个函数适用于(对于某些工作的定义),void因为lambda在我们添加时工作的原因相同-> void.它不再是一个不受限制的占位符.我们已经知道了返回类型.要获得与lambda相同的行为,请将声明更改operator()为auto.
在您的情况下,只需定义返回类型,编译器应接受它:
auto callSelf = [](auto& func) -> void {func(func);};
class wrapper : public decltype(callSelf) {
using base = decltype(callSelf);
public:
wrapper() : base(callSelf) {}
template<class T>
void operator()(T& func) {
base::operator()(func);
}
};
int main()
{
callSelf(callSelf); //works
wrapper w;
w(w); //ok, nice endless recursion
}
Run Code Online (Sandbox Code Playgroud)
使用返回类型推导,编译器不能在lambda本身中使用lambda,因为编译器必须查看函数体以推导返回类型.编译器必须检查函数体的事实使它看到使用lambda本身的lambda的内容.由于编译器处于演绎过程中,因此无法使用lambda,因此编译错误.
| 归档时间: |
|
| 查看次数: |
667 次 |
| 最近记录: |