21

考虑这个 C++ 代码片段:

namespace
{
    void f()
    {
    }

    class A
    {
        void f()
        {
            ::f(); // VC++: error C2039: 'f' : is not a member of '`global namespace''
        }
    };
}

GCC 编译得很好。Visual C++ 2008 编译失败,出现 C2039 错误。这两个编译器中的哪一个在这里是正确的?有什么方法可以正确引用“全局” f吗?

编辑: Zack 建议尝试,它适用于两种编译器。对我来说看起来有点奇怪。

namespace
{
    void f()
    {
    }

    class A
    {
        void f();
    };
}

void A::f()
{
    ::f();
}
4

2 回答 2

10

VC++ 2008 在这里是错误的。根据c++03标准3.4.3.4:

以一元作用域运算符 :: (5.1) 为前缀的名称在全局作用域中查找,在使用它的翻译单元中。该名称应在全局命名空间范围内声明,或者应是由于使用指令(3.4.3.2)而在全局范围内可见的名称。:: 的使用允许引用全局名称,即使它的标识符已被隐藏(3.3.7)。

这里的重要部分是全局命名空间中的 using 指令将使这些符号可以通过范围运算符访问。

根据 7.3.1.1/1,匿名命名空间相当于:

namespace *unique* { /* empty body */ }
using namespace *unique*;
namespace *unique* { namespace-body }

所以在这两个部分之间,独立函数应该可以在全局命名空间中访问。

于 2011-03-31T18:05:39.253 回答
7

正如 AcademicRobot 指出的那样,Visual C++ 是错误的。作为一种解决方法,添加一个空的未命名命名空间块应该可以解决问题(我没有要测试的 Visual C++ 2008,但这适用于 Visual C++ 2010):

// empty unnamed namespace to placate compiler
namespace { }

namespace {
    void f() { }
    struct A {
        void f() { ::f(); }
    };
}

我已将此问题报告给 Visual C++ 团队。

于 2011-03-31T18:36:37.737 回答