Search code examples
c++namespacesusing-directives

Accessing a global and namespace variable


I am trying to access variable x using using directive in the following code:

#include <iostream>
using namespace std;

int x = 10;

namespace e {
    int x = 5;
}

int main() {
    using namespace e; // Because of this line, the compiler shows an error
    cout << x;
    return 0;
}

In general, we use the following line to access x, but I am getting an error.

We can also use using e::x;, but my question is why can't we use using namespace e;.


Solution

  • Let's start with another example.

    const int x = 10;
    
    namespace e {
    const int y = 5;
    }
    
    int main()
    {
        std::cout << e::y;
        using namespace e;
        std::cout << y;
    }
    

    There is variable with value 10 and name x in global namespace (which can be referred to as x simply) and variable with value 5 with name y in namespace e (which must be referred to as e::y).

    By adding using namespace e;, you inject all names from namespace e into global namespace. This means global namespace now contains names x and y, and namespace e contains name y. You can now refer to variable with value 5 using both y and e::y.

    Now, back to your example. If we change y to x:

    const int x = 10;
    
    namespace e {
    const int x = 5;
    }
    
    int main()
    {
        std::cout << e::x;
        using namespace e;
        std::cout << x;
    }
    

    There is x in global namespace and x in namespace e. By adding using namespace e; you inject all the names from namespace e to global namespace, so now global namespace contains names x and x, and namespace e contains name x. See the problem? Global namespace contains two names x, which confuses the compiler. When you try to print a variable under the name x, the compiler looks up names in global namespace and finds two x. It cannot choose which one you meant, so it throws error.

    This is the main reason why using namespace (particularly using namespace std;) is considered evil. One can easily break working code by updating a library or introducing a new function. A compiler error is the best outcome in such a case, but sometimes it's possible that the compiler will silently replace one function by another, because it matches better.

    You can still access both variables using fully qualified names:

    int main()
    {
        using namespace e;
        std::cout << ::x << " "; //x from global with fully quafilied name
        std::cout << ::e::x << " "; //x from namespace e with fully qualified name
        std::cout << e::x; //not fully qualified, but not ambiguous either - only one x in namespace e
    }