3

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

#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 *)(double)”

或者

错误 C2440:“static_cast”:无法从“double (__cdecl *)(double)”转换为“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)”转换为“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 或函数时会发生这种情况。也许有人知道这些名称是如何进入我的 lambda 表达式范围的?

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

使用 Visual Studio 2010 Express 版本 10.0.40219.1 SP1Rel。

4

3 回答 3

3

使用与iny1冲突(第二类贝塞尔函数,1 阶)。这就是为什么命名空间是一件好事(sm)以及为什么不应该用. (虽然很好,恕我直言。)当然,并非所有 C++头文件都正确地将所有名称仅放在 namespace 中,但它们应该;数学库中有太多短名称。y1<cmath>std::using namespace std;using std::stringcmathstd

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


编辑:原来是 VC10 中的一个错误,它在 lambdas 中应用了不正确的名称解析规则。多次 报告 lambda 表达式中的名称解析错误,这些错误在 VC12 中被标记为已修复(话虽如此,我不知道如何找到尚未标记为已修复的错误报告)。我支持下面的建议,虽然关于使用显式this->的建议可能更具争议性,但我已经被意外的名称查找烧毁了几次,显式限定可以提供帮助。


总的来说,我的建议是:

1) 切勿使用using namespace std;

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


编辑stdC 库头文件对命名空间的使用。

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

换句话说,名称必须std::并且可能在全局命名空间中。因此,std::始终如一地使用不会受到伤害。它可能无济于事,但它也可能保护您免受某些未来标准库的影响,这些标准库不会将这些名称注入全局命名空间。

于 2012-11-06T06:24:06.917 回答
1

老实说,我看不出从 int 转换为 int 的意义。你可以简单地写:

int l = y1;

但如果你真的想将 int 转换为 int,下面的代码应该可以工作。

int l = static_cast<int>(y1); 
于 2012-11-06T04:53:24.197 回答
0

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

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

虽然是一个看似很酷的错误,但请尝试使用一个好的约定来命名变量。使它们具有描述性,但不要太长。阅读 Rob Pike 和 Kernighan 的《编程实践》一书,以更好地了解变量命名以及使用一致的样式和格式。

编辑:

#include <cmath>using namespace std;。我没有收到任何错误,但是如果我创建 aclass MyClass{};并创建一个 object MyClass y1,我会收到一条错误消息"..previous definition 'function'"。内部y1班级SimpleClass永远不会受到影响。

于 2012-11-06T04:50:38.217 回答