2

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;
}
Colin Hicks
  • 348
  • 1
  • 3
  • 13
  • Hmm. MSVC accepts the first but clang-cl doesn't. – Adrian Mole Jan 27 '21 at 17:40
  • 1
    Just FYI - I didn't downvote. I was just adding a bit of extra info for others. – Adrian Mole Jan 27 '21 at 17:47
  • @AdrianMole Sorry I was not accusing you, I just didn't know were else to add that. I would appreciate constructive criticism if you have it though. 2 down votes in about 10 minutes without much explanation is a bit frustrating. – Colin Hicks Jan 27 '21 at 17:52
  • 1
    NP. The DVs are as much a mystery to me as they are to you. But votes are anonymous on SO, and asking for explanations is generally futile. – Adrian Mole Jan 27 '21 at 17:53
  • @AdrianMole *Sigh* and once the question has two downvotes, no one is going to look at it so not only do I lose what little reputation I have, without much explanation, I probably won't get any more information as well. It can be frustrating asking questions here sometimes, I put in a lot of effort to be specific, cite other sources/questions and provide examples. I don't understand what I did wrong. – Colin Hicks Jan 27 '21 at 18:03
  • The question is good. You got my +1. It may get even better if you move the intro to the end somehow, as the question is quite clear from the code itself while the intro is a bit vague till you get to the code. Nevertheless, the question is totally legit and relevant. – Amir Kirsh Jan 27 '21 at 22:17

1 Answers1

1

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.

johnmastroberti
  • 847
  • 2
  • 12