如何正确引用匿名命名空间中的函数

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();
}

2
我并不知道确切的答案,但也许这个也算吧:使用不会隐藏外部名称的函数名称? :) - Xeo
1
我同意。这更多是一个理论问题。 - detunized
当然,我认为这非常有趣。加一赞你找到了它。 - Xeo
3
如果您将class A的定义之外的A::f提取出来,会发生什么?如果您将其完全提取出匿名命名空间声明,又会发生什么? - zwol
1
Zack, 它有效。但如果存在问题,我看到 ::A::f 可能会有问题。 - detunized
显示剩余2条评论
2个回答

10

在这里,VC++ 2008存在错误。根据C++03标准3.4.3.4:

 

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

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

根据7.3.1.1/1,匿名命名空间等价于:

namespace *unique* { /* empty body */ }
using namespace *unique*;
namespace *unique* { namespace-body }
所以在这两个部分之间,独立的函数应该可以在全局命名空间中访问。

7

正如academicRobot所指出的,Visual C++有误。 解决方法是添加一个空的未命名namespace块即可解决此问题(我没有Visual C++ 2008来测试,但这在Visual C++ 2010中有效):

// empty unnamed namespace to placate compiler
namespace { }

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

我已经向Visual C++团队报告了此问题。


感谢您的解决方案。我刚在VS2008上测试过,也能够正常工作。尽管如此,我还是接受了academicRobot的答案,因为它详细地解释了问题。在他的回答之后,您的修复方法非常合理。 - detunized

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接