Consider the following two code snippets:
#include <iostream>
namespace
{
bool foo = false;
}
bool foo = true;
int main()
{
std::cout << foo << std::endl;
}
#include <iostream>
namespace A
{
namespace
{
bool foo = false;
}
bool foo = true;
}
int main()
{
std::cout << A::foo << std::endl;
}
In Snippet A, foo
's usage inside int main()
is ambiguous, whilst in Snippet B it is not. Why is this the case?
Related: Anonymous Namespace Ambiguity
The behavior of unnamed namespaces is specified in §7.3.1.1 [namespace.unnamed]/p1:
An unnamed-namespace-definition behaves as if it were replaced by
inline_opt namespace unique { /* empty body */ } using namespace unique ; namespace unique { namespace-body }
where
inline
appears if and only if it appears in the unnamed-namespace-definition, all occurrences ofunique
in a translation unit are replaced by the same identifier, and this identifier differs from all other identifiers in the entire program.
In particular, note that the declarations inside the unnamed namespace is made visible in the surrounding scope via a using-directive using namespace unique;
.
In Snippet A, foo
is unqualified, so the compiler performs unqualified name lookup (§3.4.1 [basic.lookup.unqual]). Relevant here is paragraph 2 of the subclause:
2 The declarations from the namespace nominated by a using-directive become visible in a namespace enclosing the using-directive; see 7.3.4. For the purpose of the unqualified name lookup rules described in 3.4.1, the declarations from the namespace nominated by the using-directive are considered members of that enclosing namespace.
Hence, unqualified name lookup finds both declarations of foo
, and the name is ambiguous.
In Snippet B, A::foo
is qualified, so qualified name lookup rules apply. Since A
is a namespace, the applicable subclause is §3.4.3.2 [namespace.qual]. As relevant here, the rule is specified in paragraph 2 of that subclause:
For a namespace
X
and namem
, the namespace-qualified lookup setS(X,m)
is defined as follows: LetS'(X,m)
be the set of all declarations ofm
inX
and the inline namespace set ofX
(7.3.1). IfS'(X,m)
is not empty,S(X,m)
isS'(X,m)
; otherwise,S(X,m)
is the union ofS(Ni,m)
for all namespacesNi
nominated by using-directives inX
and its inline namespace set.
In other words, qualified name lookup considers namespaces nominated by using-directives only if the name is not found in the specified namespace and its inline namespace set. Here, the name foo
is found in namespace A
, so the unnamed namespace nominated by the using-directive is not considered, and there's no ambiguity.
If you write ::foo
instead of foo
in Snippet A, then qualified lookup rules would apply instead, and there would once again be no ambiguity.