【问题标题】:Weird bug with C++ lambda expressions in VS2010 ( variable y1 )VS2010 中 C++ lambda 表达式的奇怪错误(变量 y1)
【发布时间】:2012-11-07 01:17:18
【问题描述】:

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

#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)' 到 '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。

【问题讨论】:

  • 您可能需要发布更多代码,以便我们了解另一个 y1 在哪里以及它如何影响程序
  • 我只能说“哇!很酷的错误!”...我建议您将其报告为错误...最有可能返回 Lua 社区。 Aniket 一针见血……真正的问题(如我所见)是:“ y1 的这种替代(双重)定义(我现在简单地避免使用的名称)如何进入范围?”
  • 那有问题...我没能找到它。事实上,文本“y1”并没有出现在 Lua 文件中的任何地方,所以它可能来自其他地方,但我不知道在哪里。其中一个项目非常小(我基本上是在测试一些代码),它只链接 Lua 和标准库。
  • @corlettk 这正是我有兴趣回答的问题!你措辞完美。
  • y1 来自标准数学库 math.h(或 cmath)。这是第二类贝塞尔函数,一阶。

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


【解决方案1】:

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

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


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


总的来说,我的建议是:

1) 切勿使用using namespace std;

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


编辑 C 库头文件使用std 命名空间。

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

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

【讨论】:

  • 经过所有测试,确切的问题似乎是 lambda 在尝试将名称解析为全局对象之前将其解析为捕获的变量。我对标准不够熟悉,无法判断这实际上是错误还是预期行为,但我会说它属于“令人惊讶的行为”。避免使用命名空间 std 在我的情况下没有帮助,因为 cmath 没有将 math.h 中的所有内容放在 std 命名空间中。
  • 这似乎是一个 VS2010 的错误,按照标准的正常行为应该符合预期:stackoverflow.com/questions/12905539/…
【解决方案2】:

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

int l = y1;

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

int l = static_cast<int>(y1); 

【讨论】:

    【解决方案3】:

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

    改为:int l = static_cast&lt;int&gt;(y1);

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

    编辑:

    #include &lt;cmath&gt;using namespace std;。我没有收到任何错误,但是如果我创建一个 class MyClass{}; 并创建一个对象 MyClass y1,我会收到一个错误说明 "..previous definition 'function'"y1 内部类 SimpleClass 永远不会受到影响。

    【讨论】:

    • 哦。我猜它被删除是因为它被识别为标签?我可能没有正确格式化代码文本。好吧,就像我说的我也无法在新项目中重现它,但感谢您的检查。
    • @AndreiTita:不要使用&lt;code&gt; 标签,因为它会破坏格式。如果已编辑问题。
    • 其实我之前用的是
      ,后来换成了,现在看起来不错。好吧,不管怎样。
    猜你喜欢
    • 1970-01-01
    • 2011-01-02
    • 2014-02-20
    • 2018-10-30
    • 2023-03-26
    • 2013-01-05
    • 2013-05-24
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多