8
struct A{};
int A;
struct A a;
struct A::A b;

The last two declarations above are equivalent.They both declare objects of type A. Where in the Standard can I find or deduce this?

Leon
  • 868
  • 4
  • 12
  • 3
    I think there may be cases where those last two are _not_ equivalent... – Mooing Duck Apr 17 '15 at 17:29
  • 2
    Are you looking for the specification of the *injected class name* used in the second? Or the specification that the *elaborated type name* `struct A` refers unambiguously to the type, not the variable? – Mike Seymour Apr 17 '15 at 17:30
  • 1
    @MooingDuck: Indeed, if there's a namespace `A` containing a different class `A`, then the second would denote that. – Mike Seymour Apr 17 '15 at 17:37
  • @MikeSeymour I don't think that's possible. – Columbo Apr 17 '15 at 17:44
  • 1
    @Columbo: [I disagree](http://ideone.com/x3HSoR). You can't declare the namespace in the same scope as the class, but you can bring it into scope with `using`. – Mike Seymour Apr 17 '15 at 17:44
  • @MikeSeymour [Clang disagrees with you](http://coliru.stacked-crooked.com/a/bae3ed6ce75527fb) – Columbo Apr 17 '15 at 17:47
  • 1
    @Columbo: Good for Clang. Unfortunately, it's too late on a Friday for me to care which is right. – Mike Seymour Apr 17 '15 at 17:47
  • @MikeSeymour http://stackoverflow.com/questions/29883977/ambiguous-name-lookup-with-using-directive So yeah, not possible. – Columbo Apr 26 '15 at 21:58

1 Answers1

9

[class]/2:

A class-name is inserted into the scope in which it is declared immediately after the class-name is seen. The class-name is also inserted into the scope of the class itself; this is known as the injected-class-name.

I.e. A::A::A::A refers to A as well. In some contexts, A::A could name the constructor instead, though - [class.qual]/2 covers this, and its note even addresses your example:

In a lookup in which function names are not ignored33 and the nested-name-specifier nominates a class C

  • if the name specified after the nested-name-specifier, when looked up in C, is the injected-class-name of C (Clause 9), or
  • in a using-declaration (7.3.3) that is a member-declaration, if the name specified after the nested-name- specifier is the same as the identifier or the simple-template-id’s template-name in the last component of the nested-name-specifier,

the name is instead considered to name the constructor of class C. [ Note: For example, the constructor is not an acceptable lookup result in an elaborated-type-specifier so the constructor would not be used in place of the injected-class-name. — end note ]


33) Lookups in which function names are ignored include names appearing in a nested-name-specifier, an elaborated-type- specifier, or a base-specifier.

So in a statement such as

A::A a;

Function names are not ignored when looking up A::A, and thus the code is ill-formed as A::A refers to the constructor. However, in

struct B : A::A {};
struct A::A a;

Everything is fine as function names are ignored in base-specifiers and elaborated-type-specifiers.

Columbo
  • 60,038
  • 8
  • 155
  • 203
  • I know this paragraph. But how did you deduce from it that A::A is equivalent to the type A in the above declaration? – Leon Apr 17 '15 at 17:34
  • @Leon That’s what that paragraph says. – Konrad Rudolph Apr 17 '15 at 17:34
  • @LeonTrotski ... the name `A` is declared inside the scope of the class `A`, hence the qualified-id `A::A` can refer to said name. – Columbo Apr 17 '15 at 17:35
  • Doesn't `A::A` always refer to the constructor, unless a disambiguating `struct` precedes it? – Cornstalks Apr 17 '15 at 17:38
  • @Columbo But why the declaration `A::A *p1;` is not valid, as in `struct A{}; A::A *p1; A* p2;`? – Leon Apr 17 '15 at 17:47
  • 1
    @LeonTrotski: That's a context in which function names are not ignored. In that context, it refers to the constructor (see section 3.4.3.1) ([and this question](http://stackoverflow.com/questions/29681449/program-being-compiled-differently-in-3-major-c-compilers-which-one-is-right/29681754#29681754)). – Cornstalks Apr 17 '15 at 17:48
  • 1
    @LeonTrotski Because that's one of the contexts where `A::A` is naming the constructor instead :) – Columbo Apr 17 '15 at 17:48
  • 1
    @Columbo: Great, thanks! I just found that `A::A` should refer to the class, not the constructor, in "a *nested-name-specifier*, an *elaborated-type-specifier*, or a *base-specifier*." For example: `struct B : A::A {};` (here `A::A` refers to the class, not the constructor). You are right indeed! – Cornstalks Apr 17 '15 at 17:50
  • @Columbo Let me see if I understood this correctly. So you're saying that `A::A a;` is ill-formed because of footnote (33) and the fact that this declaration doesn't define a constructor for `A`? – Leon Apr 17 '15 at 18:05
  • @LeonTrotski Err, what!? Not quite. `A::A a;` is ill-formed because `A::A` names the (implicitly-declared) constructor of `A` but not the type `A`, since function names are not ignored in this context. – Columbo Apr 17 '15 at 18:08
  • `function names are not ignored in this context` - and that is because of footnote 33. Isn't that true? Also, if the declaration `A::A a;` were replaced by `A::A(){}`, it would be valid because it would define the constructor for `A`. That's what I said in my prior comment. – Leon Apr 17 '15 at 18:20
  • @LeonTrotski Footnotes aren't normative, anyway. Also, yeah, I partially misunderstood your comment then. – Columbo Apr 17 '15 at 18:31