c++scopenamespaceslanguage-lawyerusing-declaration

Rules regarding using declarations c++


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;
}

Solution

  • Technically, the example you've given does compile, but it fails to link. The issue is the line

    extern int i;
    

    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 of i 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" the X::i which is visible at global scope, so we get the instruction

    mov     DWORD PTR i[rip], 2
    

    whereas without the extern declaration, we get

    mov     DWORD PTR X::i[rip], 2
    

    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 of i to use here, and while X::i is defined at global scope, i is not.