4

According to https://en.cppreference.com/w/cpp/language/injected-class-name

In a class scope, the name of the current class is treated as if it were a public member name; this is called injected-class-name. The point of declaration of the name is immediately following the opening brace of the class definition.

int X;
struct X {
    void f() {
        X* p; // OK. X refers to the injected-class-name
        ::X* q; // Error: name lookup finds a variable name, which hides the struct name
    }
};

So what is really happening in the code? Is X* p turned into X::X* p?

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
csguy
  • 1,354
  • 2
  • 17
  • 37

2 Answers2

6

So what is really happening in the code? Is X* p turned into X::X* p?

Basically. The name lookup rules start in the narrowest scope. When you do X* p; in f is looks in f's scope and doesn't find anything. Then it checks X's scope since f is scoped to X. It finds X since it is injected into the class scope so it stops there and you get the class type.

When you do ::X* q; then ::X says look for X in the global namespace, and there is finds a variable, not a type so you get an error.

NathanOliver
  • 171,901
  • 28
  • 288
  • 402
  • So the reason why something like `X::X::foo` can occur (something like: https://stackoverflow.com/questions/46805449/why-is-the-code-foofoofoofoob-compiling?noredirect=1&lq=1) is because Injected-Class-Name ignores those scope lookups and simply does X::foo? – csguy Jan 28 '20 at 20:09
  • @csguy It doesn't ignore it per se, it's just that `X::` contains `X` and `f` in this case. `X` because it is injected via the compiler and `f` because you defined it. If you do `X::X` then your right back to where you started and again have `X` and `f` as valid names. Make sense? – NathanOliver Jan 28 '20 at 20:11
  • Oh I see. `X` is injected because it's not stated as some member name because it's just the class name? – csguy Jan 28 '20 at 20:14
  • @csguy When you create a class, the compiler makes the class name a member of the class. So `class_name::class_name` is always valid an since `class_name::class_name` is `class_name`, you can again access it's members and keep going like `X::X::X::X::X::X::X::X::X::X::X::X::X::f();` if you really want to. – NathanOliver Jan 28 '20 at 20:15
  • And that's specifically because of Injected-Class-Name right? – csguy Jan 28 '20 at 20:16
  • 1
    Yes. If the name were not injected then `class_name::class_name` would no be valid (constructors are not accessible) – NathanOliver Jan 28 '20 at 20:17
  • Now that I understand this, referring to your answer, when you say that `X* p` essentially becomes `X::X* p`, this is because `X` is injected as a member of the class so and variable declared with `X` will refer to it right? This would be more visible in templates where the type `X` for example is injected and all `X` in the template will refer to `X` – csguy Jan 28 '20 at 20:28
  • 1
    @csguy Yep. Isn't C++ fun? ;) – NathanOliver Jan 28 '20 at 20:37
4

This qualified name ::X is searched in the global namespace. As there is no type with such a name (the variable declaration hides the type struct X) the compiler issues an error.

You could use an elaborated name like

int X;
struct X {
    void f() {
        X* p; // OK. X refers to the injected-class-name
        struct ::X* q; // OK. elaborated name struct ::X
    }
};
Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335