Search code examples
c++language-lawyerusing-directivesname-lookup

Name-lookup ambiguity inconsistency


I'm trying to understand why this program does not give an name-lookup ambiguity for i:

namespace X { int i = 1; }

namespace Q {    
    namespace P {        
        int i = 2;
        using namespace X;
    }

    using namespace P;

    int l = i;
}

int main() {}

If we modify it like this we get a name-lookup ambiguity:

namespace X { int i = 1; }

namespace P {        
    int i = 2;
    using namespace X;
}

using namespace P;

int l = i;

int main() {}

The only change I made here is to remove the namespace Q and place it's content in the global namespace instead.

I have tried with 3 different compilers:

The all give the results stated in this email, and i'm trying to find out why.

Can anyone explain the behaviour in terms of the c++ standard? I fail to understand it.


Solution

  • In the first program used variable i is defined in namespace P because the using directive

    using namespace X;
    

    places declarations of X in the global namespace (the common namepsace for X and P). Thus the declaration of i in P (more precisely in Q due to another using directive) hides the declaration of X::i in the global namespace.

    From the C++ Standard (3.4.1 Unqualified name lookup)

    2 The declarations from the namespace nominated by a using-directive become visible in a namespace enclosing the using-directive; see 7.3.4.

    So we have for the first program

    namespace X { int i = 1; }
    
    namespace Q {    
        namespace P {        
            int i = 2;
            using namespace X; // 1
        }
    
        using namespace P; // 2
    
        int l = i;
    }
    

    that the enclosing namespace for using directive #1 is the global namespace and the enclosing namespace for using directive #2 is the namepsace Q.

    In the second program the both definitions of i are placed in the global namespace due to these two using directives

    //...
    using namespace X;
    //...
    using namespace P;