使用嵌套lambda时出现奇怪的编译错误

Strange compilation error in usage of nested lambda

本文关键字:编译 错误 嵌套 lambda      更新时间:2023-10-16

我已经在vc2010上使用lambda编写了一些代码。代码的简化结构如下:

template<typename Functor>
bool f1(int a, Functor& f)
{
    return f(a+1);
}
template<typename Functor>
bool f2(Functor& f)
{
    return f(1);
}
template<typename Functor>
bool f3(Functor& f)
{
    return f2([&](int a) -> bool {
        // (1) Works
        auto test = [&](int b) -> bool { return f(a+b); };
        return f1(a, test);
        // (2) Doesn't work         
        //return f1(a, [&](int b) -> bool { return f(a+b); });
    });
};
int main()
{
    int a = 100;
    f3([&](int b) { return (a+b)%2 == 0; });
}

首先,我编写了一个嵌套的lambda代码,如(2)所示,vc10给出了一个无法理解的错误消息,如下面的

'f1' : cannot convert parameter number from 'int' to 'int &'

然而,代码(1)运行良好,除了lvalue-ness之外,它与(2)相同。

我的问题是:

  1. 代码(2)是否符合C++11标准
  2. 如果没有,这种奇怪的编译行为的原因是什么
return f1(a, [&](int b) -> bool { return f(a+b); });

这里,第二个参数是lambda,它是一个临时对象,不能绑定到非常量引用。我认为,错误信息具有误导性;它并不能完全说明问题所在。一个好的编译器会打印出更好的错误消息。试试GCC或Clang。

修复方法是:使第二个参数不引用:

template<typename Functor>
bool f1(int a, Functor f)  //I removed `&` from the second parameter
{
    return f(a+1);
}

同样,使其他函数中的所有Functor参数都不被引用。传递函子作为引用没有多大意义,尤其是在C++11中,在C++中,您也可以传递lambda,您可以动态定义lambda。

GCC 4.6给出以下错误:

a.cpp:在函数"int main()"中:
a.cpp:30:43:错误:对"f3(main()::<lambda(int)>)"的调用没有匹配的函数
a.cpp:30:43:注:候选人为:
a.cpp:14:6:注:bool f3(Functor&)[其中Functor=main()::<lambda(int)>]
a.cpp:14:6:注意:参数1从"main()::<lambda(int)>"到"main()::<lambda(int)>&"没有已知的转换

更清楚的是:您的lambda是临时的,您正试图将它们绑定到l-value引用。所以只使用r值引用或根本不使用引用:

template<typename Functor>
bool f1(int a, Functor&& f)
{
    return f(a+1);
}
template<typename Functor>
bool f2(Functor&& f)
{
    return f(1);
}
template<typename Functor>
bool f3(Functor&& f)
{
    return f2([&](int a) -> bool {
        // (1) Works
        auto test = [&](int b) -> bool { return f(a+b); };
        return f1(a, test);
        // (2) Doesn't work         
        //return f1(a, [&](int b) -> bool { return f(a+b); });
    });
};
int main()
{
    int a = 100;
    f3([&](int b) { return (a+b)%2 == 0; });
}

不知道VS是否可以编译这个,但GCC做得很好。

正如其他人所说,您不能将临时引用绑定到非常量引用。

有三种方法可以解决这个问题:

  1. 传递值:

    模板布尔f1(int a,函数f){返回f(a+1);}

  2. 传递右值:

    模板布尔f1(int a,函数&&f){返回f(a+1);}

  3. 传递左值:

    模板bool f1(int a,const Functor&f){返回f(a+1);}

我会选择第三个选项(通过左值或常量引用)。