How does the name lookup work in this case?

Discussion in 'C++' started by Peter, Jan 28, 2014.

  1. Peter

    Peter Guest

    Consider this definition (namespace and class share the same name):

    namespace Foo
    {
    int x;

    class Foo
    {
    public:
    static int x;
    };

    int Foo::x;
    }

    I wondered what Foo::x would refer to with "using" directive used for namespace Foo: a global variable x in namespace Foo or static member of class Foo? Basically, I assumed the following code would not compile:

    int main()
    {
    using namespace Foo;
    Foo::x;
    return 0;
    }

    My reasoning went like this:

    - Foo::x is a global variable x from namespace Foo
    - Foo::Foo::x is a static member of class Foo from namespace Foo, but since
    "using" directive is applied, the namespace name can be omitted, thus Foo::x is also a static member of class Foo
    - conclusion: call to Foo::x in main() is ambiguous - it refers to two different entities

    However, the compiler I tested it with (one of g++ recent versions) had no trouble disambiguating this: experiments showed Foo::x in main() is interpreted as global variable x in namespace Foo. Moreover, if I remove the definition of global x from namespace Foo, then the compiler emits the followingerror:

    main.cpp: In function 'int main()':
    main.cpp:16:4: error: 'x' is not a member of 'Foo'
    Foo::x;

    so it doesn't find the static member of class Foo. In order for the compiler to find it I have to qualify it fully as Foo::Foo::x despite the "using namespace Foo;" line. Why? How does the lookup work here?
     
    Peter, Jan 28, 2014
    #1
    1. Advertisements

  2. I think that is correct.

    And I think probably C++11 §7.3.4/6, in the "Using directive" section,
    applies:

    "If name lookup finds a declaration for a name in two different
    namespaces, and the declarations do not declare the same entity and do
    not declare functions, the use of the name is ill-formed."

    As it happens Visual C++ 12.0 appears to also think so:

    [error]
    original.cpp(19) : error C2872: 'Foo' : ambiguous symbol
    could be 'Foo'
    or 'original.cpp(8) : Foo::Foo'
    [/error]

    Except that I believe that's wrong, it's reasonable: maybe its how the
    language should be.

    That's not full qualification, and Visual C++ still emits the diagnostic
    above.

    Full qualification is

    ::Foo::Foo::x;

    and this is accepted by Visual C++.

    I think the ambiguity is real and that the g++ failure to diagnose it is
    a compiler bug. I could be wrong. But, since the two compilers disagree,
    at least one of Visual C++ and g++ has a bug here. ;-)

    C++11 §7.3.4/2

    "A using-directive specifies that the names in the nominated namespace
    can be used in the scope in which the using-directive appears after the
    using-directive. During unqualified name lookup (3.4.1), the names
    appear as if they were declared in the nearest enclosing namespace which
    contains both the using-directive and the nominated namespace"


    Cheers & hth.,

    - Alf
     
    Alf P. Steinbach, Jan 28, 2014
    #2
    1. Advertisements

  3. Peter

    Peter Guest

    In order for the compiler to find it I have to qualify it fully as
    Perhaps a silly question, but what's the difference
    between ::Foo::Foo::x and Foo::Foo::x here?
    I thought they were equal in this context.
    I also think this may be a g++ bug (unless there's yet another
    obscure C++ rule according to which the compiler isn't supposed to
    interpret Foo::x as static member of class Foo in this case).
     
    Peter, Jan 30, 2014
    #3
  4. Peter

    Öö Tiib Guest

    On Thursday, 30 January 2014 20:09:52 UTC+2, Peter wrote:

    Attribute quotes, please.
    The difference is what Alf said, one is fully qualified name
    and other is not. Other 'x' in context of your question is
    '::Foo::x' when fully qualified.
     
    Öö Tiib, Jan 31, 2014
    #4
  5. Peter

    Peter Guest

    Peter, Jan 31, 2014
    #5
  6. Peter

    Öö Tiib Guest

    My opinion is that usage of unqualified name 'Foo' after doing
    'using namespace Foo;' that contains other 'Foo' is ambiguous.
    So even when one of the '::Foo::Foo::x' or '::Foo::x' is not
    available it should not compile. I'm not sure how gcc looks it
    up. Perhaps it tries to be overly smart somewhere.

    I tried with clang, it did also reject the code.
     
    Öö Tiib, Jan 31, 2014
    #6
    1. Advertisements

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments (here). After that, you can post your question and our members will help you out.