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. Advertising

  2. On 28.01.2014 21:47, Peter wrote:
    > 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


    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]


    > 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 following error:
    >
    > 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.


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


    > In order for the compiler to find it I have to qualify it fully as
    > Foo::Foo::x despite the "using namespace Foo;" line.


    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++.


    > Why?


    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. ;-)


    > How does the lookup work 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. Advertising

  3. Peter

    Peter Guest

    > > In order for the compiler to find it I have to qualify it fully as
    >
    > > Foo::Foo::x despite the "using namespace Foo;" line.

    >
    >
    >
    > 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++.
    >


    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 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. ;-)
    >


    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.

    >On Tuesday, 28 January 2014 23:32:52 UTC+2, Alf P. Steinbach wrote:
    > > Full qualification is
    > >
    > > ::Foo::Foo::x;
    > >

    >
    > 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.


    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

    On Friday, 31 January 2014 21:52:57 UTC+2, Peter wrote:
    > Getting back to the main point of the thread...
    > as Alf pointed out, since g++ and Visual C++
    > respond to my code differently, then at least
    > one of them handles it wrong. Any opinions
    > on which (if any) is correct?


    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. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Steve Franks
    Replies:
    2
    Views:
    1,282
    Steve Franks
    Jun 10, 2004
  2. Tee
    Replies:
    3
    Views:
    7,905
    Herfried K. Wagner [MVP]
    Jun 23, 2004
  3. wenmang
    Replies:
    1
    Views:
    518
    Victor Bazarov
    Aug 8, 2003
  4. neverhoodboy
    Replies:
    1
    Views:
    473
    Johannes Schaub
    Mar 4, 2012
  5. Jack

    case insensitive hash lookup

    Jack, Oct 2, 2006, in forum: Perl Misc
    Replies:
    4
    Views:
    788
Loading...

Share This Page