I have this piece of code
#include <iostream>
namespace ns{
int a = 10;
}
using namespace ns;
int a = 20;
int main(){
std::cout << a;
}
As per my understanding, when std::cout << a
is evaluated, a
is searched for in main
's local scope. If not found, the lookup is performed in the global scope, where a
is found. So, I was simply expecting it to print 20
, but the code doesn't compile, claiming that
error: reference to 'a' is ambiguous
However, this code works :
#include <iostream>
namespace ns{
int a = 10;
}
using namespace ns;
int a = 20;
int main(){
std::cout << ::a;
}
It prints 20
. Why does this difference arise? Shouldn't the two codes be equivalent, considering that a
is not defined in main
's scope, and the lookup is performed in the global scope in both the cases?
This is related to a similar question, but I want to specifically understand the difference caused by replacing a
with ::a
and how the two are not equivalent, rather than just ambiguous variable references.
Take a look at https://en.cppreference.com/w/cpp/language/namespace, particularly the
Using-directive does not add any names to the declarative region in which it appears (unlike the using-declaration), and thus does not prevent identical names from being declared.
Since you're "only" doing a using ns
instead of a using ns::a
, you're not introducing the a
into the global namespace. You are just telling the compiler to search the ns
namespace in addition to the global one.
Thus, when you declare the a
variables, there is no problem because one is in ns
and one is in the global namespace. However, when you lookup an unqualified a
, then all the ns
members are considered to be part of the global namespace as well (because of the using
), so now there are two a
in the same namespace.
In your second example, the ::a
explicitly tells to use the global namespace; it's not an unqualified lookup anymore. For this, the https://en.cppreference.com/w/cpp/language/qualified_lookup has this to say:
Qualified lookup within the scope of a namespace N first considers all declarations that are located in N ... If there are no declarations in that set then it considers declarations in all namespaces named by using-directives found in N ...
In other words, the "using" namespaces are considered AFTER the actual namespace, so there's no ambiguity anymore.