21

Consider this fragment of C++ code:

namespace
{
    void f()
    {
    }

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

GCC compiles this just fine. Visual C++ 2008 fails to compile spitting out the C2039 error. Which one of these two compilers is correct here? Is there any way to reference that "global" f properly?

Edit: Zack suggested to try and it works with both compilers. Looks a bit weird to me.

namespace
{
    void f()
    {
    }

    class A
    {
        void f();
    };
}

void A::f()
{
    ::f();
}
Dan Moulding
  • 211,373
  • 23
  • 97
  • 98
detunized
  • 15,059
  • 3
  • 48
  • 64
  • 2
    Not that I know a real answer, but maybe that also counts: Use function names that don't hide the outer names? :) – Xeo Mar 31 '11 at 17:35
  • 1
    I agree. This is more of a theoretical question. – detunized Mar 31 '11 at 17:36
  • Sure, and I think it's pretty interesting. +1 for finding that. – Xeo Mar 31 '11 at 17:39
  • 3
    What happens if you pull the definition of `A::f` outside `class A`? What if you pull it all the way out of the anonymous namespace declaration? – zwol Mar 31 '11 at 17:40
  • @Zack: That works! Edit: If you pull it all the way out of the anonymous namespace, not if it's still inside but out of the `class A` – Xeo Mar 31 '11 at 17:42
  • 1
    Zack, it works. But I see possible problems with `::A::f`, if there's one. – detunized Mar 31 '11 at 17:45
  • Yeah, I can see that being an issue. Also, to be clear, I don't know which compiler is *correct*. I just guessed that MSVC++ might be treating the anonymous namespace members as not `using`-ed into the global namespace until after the anon namespace is closed. – zwol Mar 31 '11 at 17:53

2 Answers2

10

VC++ 2008 is wrong here. According to the c++03 standard 3.4.3.4:

A name prefixed by the unary scope operator :: (5.1) is looked up in global scope, in the translation unit where it is used. The name shall be declared in global namespace scope or shall be a name whose declaration is visible in global scope because of a using-directive (3.4.3.2). The use of :: allows a global name to be referred to even if its identifier has been hidden (3.3.7).

The important part here is that a using directive in the global namespace will make those symbols accessible with the scope operator.

And according to 7.3.1.1/1, an anonymous namespace is equivalent to:

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

So between these two sections, the standalone function should be accessible in global namespace.

Mark B
  • 95,107
  • 10
  • 109
  • 188
academicRobot
  • 6,097
  • 1
  • 31
  • 29
7

As academicRobot points out, Visual C++ is wrong. As a workaround, adding an empty unnamed namespace block should resolve the issue (I don't have Visual C++ 2008 to test, but this works in Visual C++ 2010):

// empty unnamed namespace to placate compiler
namespace { }

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

I've reported the issue to the Visual C++ team.

James McNellis
  • 348,265
  • 75
  • 913
  • 977
  • Thanks for the solution. I just tested it on VS2008 and it works there as well. I accepted the academicRobot's answer though, since it explains in details the problem. Your fix makes perfect sense after his answer. – detunized Apr 01 '11 at 09:30