VS2010中的C ++ lambda表达式的奇怪错误(变量y1)

时间:2012-11-06 04:44:56

标签: c++ visual-studio-2010 lambda

在我的几个项目中,代码如下:

#include <functional>

class SmallClass
{
public:
    int x1, y1;

    void TestFunc()
    {
        auto BadLambda = [&]()
        {
            int g = x1 + 1; //ok
            int h = y1 + 1; //c2296

            int l = static_cast<int>(y1); //c2440
        };

        int y1_copy = y1; //it works if you create a local copy
        auto GoodLambda = [&]()
        {
            int h = y1_copy + 1; //ok
            int l = this->y1 + 1; //ok
        };
    }
};

产生

  

错误C2296:'+':非法,左操作数的类型为'double(__ cdecl   *)(双)'

或者

  

错误C2440:'static_cast':无法转换为'double(__ cdecl   *)(double)'to'int'

你得到了照片。如果按价值捕捉也会发生。

错误似乎与成员名称“y1”相关联。它发生在不同的类,不同的项目和(看似)y1的任何类型;例如,这段代码:

[...]
MyClass y1;

void TestFunc()
{
    auto BadLambda = [&]()->void
    {
        int l = static_cast<int>(y1); //c2440
    };
}

生成这两个错误:

  

错误C2440:'static_cast':无法从'MyClass'转换为'int'否   可以执行此操作的用户定义转换运算符   转换,或者不能调用运算符

     

错误C2440:'static_cast':无法转换为'double(__ cdecl   *)(double)'to'int'没有可以进行此转换的上下文

它似乎与“功能”库相关联。它发生在我的机器上(在我的机器上)只包含“功能”(是的,它应该在括号之间,但我在HTML中失败)。

它似乎不是一个已知的错误,我不知所措。关于为什么会这样的想法? (我不需要解决方法;代码中已经有一些)。

编辑:它确实与math.h中的函数有关:

_CRT_NONSTDC_DEPRECATE(_cabs) _CRTIMP double __cdecl cabs(In struct _complex _X); _CRT_NONSTDC_DEPRECATE(_j0) _CRTIMP double __cdecl j0(In double _X); _CRT_NONSTDC_DEPRECATE(_j1) _CRTIMP double __cdecl j1(In double _X); _CRT_NONSTDC_DEPRECATE(_jn) _CRTIMP double __cdecl jn(In int _X, In double _Y); _CRT_NONSTDC_DEPRECATE(_y0) _CRTIMP double __cdecl y0(In double _X); _CRT_NONSTDC_DEPRECATE(_y1) _CRTIMP double __cdecl y1(In double _X); _CRT_NONSTDC_DEPRECATE(_yn) _CRTIMP double __cdecl yn(In int _X, In double _Y);

使用任何这些函数名称都会触发错误。包含math.h,cmath或functional时会发生这种情况。也许有人知道这些名字是如何进入我的lambda表达式的范围的?

编辑:已解决。这是VS2010中的lambda名称解析问题(可能还有其他较旧的编译器)。如果定义全局名称或使用“using namespace x”,则避免在lambdas中使用非限定名称。

使用Visual Studio 2010 Express版本10.0.40219.1 SP1Rel。

3 个答案:

答案 0 :(得分:3)

使用y1y1中的<cmath>冲突(第二种贝塞尔函数,第1阶段)。这就是为什么std::命名空间是一件好事(sm)以及为什么它不应该被using namespace std;规避的原因。 (using std::string很好,但是,imho。)当然,并非所有C ++ cmath标题都只在名称空间std中正确放置所有名称,但它们应该;数学库中有太多的短名称。

C ++名称解析规则很复杂,我不会假装理解所有尘埃落定的小角落。 lambda中的非限定名称很可能不会以与成员函数实际主体中的非限定名称完全相同的方式查找。在成员函数之外,非限定名称只能引用已经声明的类成员。 (this->y1不是一个不合格的名字。)


编辑:原来这是VC10中的一个错误,它在lambdas中应用了错误的名称解析规则。 lambda表达式中的名称解析错误被报告several times但这些错误在VC12中被标记为已修复(已经说过,我不知道如何查找未标记为已修复的错误报告)。我支持下面的建议,虽然关于使用显式this->的建议可能更具争议性,但我已经被意外的名称查找和明确的资格认证所焚烧了几次。


总的来说,我的建议是:

1)切勿使用using namespace std;

2)如果这是你的意思,请始终使用this->。 (或者,至少对类数据成员使用尾随_约定。)


编辑 C库标题使用std命名空间。

  

17.6.1.2(4):但是,在C ++标准库中,声明(除了在C中定义为宏的名称除外)都在命名空间std的命名空间范围(3.3.6)内。未指定这些名称是否首先在全局命名空间范围内声明,然后通过显式using-declarations(7.3.3)注入到命名空间std中。

换句话说,名称​​必须位于std::可能位于全局命名空间中。因此,始终使用std::并不会造成伤害。它可能没有帮助,但它也可以保护您免受未将这些名称注入全局命名空间的未来标准库的影响。

答案 1 :(得分:1)

老实说,我没有看到从int转换为int的重点。你可以简单地写一下:

int l = y1;

但是如果你真的想将int转换为int,那么下面的代码就可以了。

int l = static_cast<int>(y1); 

答案 2 :(得分:0)

该类编译在我的VS2010上,我只编辑了一行:int l = static_cast(y1); //c2440

已更改为:int l = static_cast<int>(y1);

虽然看似很酷的bug,但请尝试使用一个好的约定来命名变量。使它们具有描述性但不会太长。阅读Rob Pike和Kernighan撰写的“编程实践”一书,以便更好地了解命名变量并使用一致的样式和格式。

编辑:

#include <cmath>using namespace std;。我没有收到任何错误,但如果我创建了class MyClass{};并创建了一个对象MyClass y1,则会收到一条错误,指出"..previous definition 'function'"。内部y1内的SimpleClass不会受到影响。