Eliminating the undefined behaviour:
namespace A
{
int i = 7;
}
namespace B
{
using namespace A;
int tmp = i + 11;
int i = tmp;
}
#include <iostream>
int main()
{
std::cout << A::i << " " << B::i << std::endl;
return 0;
}
The meaning of the standard is that at the line
int tmp = i + 11;
the name i
appears in the "nearest enclosing namespace which contains both the using-directive and the nominated namespace"; the using-directive appears in namespace B
while the nominated namespace is namespace A
; the nearest enclosing namespace is the global namespace, so i
appears as ::i
. This means that if a name i
is already present in the global namespace the code is ambiguous.
For a more complex example:
namespace A {
namespace B {
namespace C {
int i = 4;
}
}
namespace D {
using namespace B::C;
namespace E {
int j = i;
}
}
}
At the line int j = i
, i
appears in the nearest enclosing namespace of the using-directive (i.e., A::D
) and the nominated namespace (A::B::C
), which is A
. So, within A::D
after the using-directive, and so also within A::D::E
, the unqualified name i
can refer to A::B::C::i
appearing as A::i
, shadowing any ::i
, conflicting with any A::i
, and being shadowed by any A::D::i
or A::D::E::i
(within A::D::E
):
int i = 1; // shadowed by A::B::C::i appearing as A::i
namespace A {
int i = 2; // conflicts with A::B::C::i appearing as A::i
namespace B {
int i = 3; // irrelevant
namespace C {
int i = 4; // nominated; appears as A::i
}
}
namespace D {
int i = 5; // shadows A::B::C::i appearing as A::i
using namespace B::C;
namespace E {
int i = 6; // shadows A::B::C::i appearing as A::i
int j = i;
}
}
}
Note that just because the name appears as A::i
during unqualified name lookup, that does not mean that it actually is there; the qualified name A::i
will continue to refer only to an actual name A::i
(if any exists).
i
instances inside ofnamespace B
refer to the same variable (it shadowsA::i
as soon as its declarator is seen, that is, before the initializer). So it is initialized with its own garbage value incremented by 11. – InfluentA::i
afterusing namespace A
. Is this what the paragraph from the standard is talking about? – Gobangi
in the expression, it takes it from lookup. And since C++ allows you to refer to variables you just defined even in the initialization expression, thei
will be the new one, not the one fromA
. – Hartmanconst
qualifiers it knows the values at compile time, I don't see why you think it must be taking place at compile time. In any event, the example provokes undefined behavior, which means the entire program is undefined ( blog.llvm.org/2011/05/… and posts linked to from there) and could do anything at all, including outputting nothing at all, outputting the text of "Romeo and Juliet," etc. – Shellfishusing namespace A
is to make names defined in A accessible as if they were defined in the global namespace. You can try to define::i
and removeusing namespace A
, the effect will be exactly the same. – Influentint i
innamespace B
shouldn'ti
be zero-initialized? – Gobang