After reading the accepted answer from this question, I thought I understood why the program failed, since the using directive does not actually declare the entity i
in the region. However names introduced by a using declaration can be used just like any other name and acts like a declaration.
With GCC, this fails
#include <iostream>
namespace X { int i = 1; }
using X::i;
int main() {
extern int i;
i = 2;
std::cout<<i;
}
But this is accepted
#include <iostream>
int i;
int main() {
extern int i;
i = 2;
std::cout<<i;
}
Technically, the example you've given does compile, but it fails to link. The issue is the line
What you're telling the compiler/linker here is "there will be a variable
i
defined somewhere else in the program, so, compiler, don't worry if you can't find the definition. Linker, I expect you to find the definition ofi
once you have all of the object files and link that in here."We can see this in action using compiler explorer:
Without the extern declaration
With the extern declaration
In the second case, the declaration of
i
"shadows" theX::i
which is visible at global scope, so we get the instructionwhereas without the extern declaration, we get
though I'm not totally sure on the shadowing part, as neither gcc nor clang warns about that with
-Wshadow
. In any case, we see now why the second example fails to link: the linker is trying to find the definition ofi
to use here, and whileX::i
is defined at global scope,i
is not.