8

My understanding was that a friend declaration could also serve as a forward declaration for a class if the class specifier was used, as in this example:

class A
{
    friend class B;
    B* b;
};

class B {};

int main() {}

However, g++ (4.6.3 and 4.7.0) gives me the following error (g++-4.7 should have support for extended friend declarations), which is expected without a forward declaration:

main.cpp:6:2: error: ‘B’ does not name a type

In an attempt to confirm my expectations that the friend class B; should serve as a forward declaration, I found this answer and this answer, but neither was conclusive (or I couldn't conclude much from them at least) so I attempted to consult the c++11 standard and found this example:

class X2 {
    friend Ct; // OK: class C is a friend
    friend D; // error: no type-name D in scope
    friend class D; // OK: elaborated-type-specifier declares new class
}

Based on my reading of the the third declaration, my friend class B should be an elaborated-type-specifier declaring a new class.

I am just starting to understand official standard wording, so I must be missing something. What am I misunderstanding?

Community
  • 1
  • 1
JaredC
  • 5,150
  • 1
  • 20
  • 45

2 Answers2

7

Your friend class B; declaration does serve as a forward declaration, but such declaration is not found by name lookup until a matching declaration is provided.

[class.friend]/11:

If a friend declaration appears in a local class (9.8) and the name specified is an unqualified name, a prior declaration is looked up without considering scopes that are outside the innermost enclosing non-class scope. For a friend function declaration, if there is no prior declaration, the program is ill-formed. For a friend class declaration, if there is no prior declaration, the class that is specified belongs to the innermost enclosing non-class scope, but if it is subsequently referenced, its name is not found by name lookup until a matching declaration is provided in the innermost enclosing nonclass scope.

K-ballo
  • 80,396
  • 20
  • 159
  • 169
  • No, it really is `::B`: http://ideone.com/bEgZrq . Note "the innermost enclosing *non-class* scope". – aschepler Jan 01 '13 at 23:08
  • @K-ballo So when it says declares a new class, is that solely for the purposes of the friend declaration, but not for the benefit of anything else? – JaredC Jan 01 '13 at 23:30
  • @K-ballo Then that's where my confusion was. I assumed that *declares* meant that it also brought the name into scope and overlooked the *its name is not found by name lookup until a matching declaration is provided* part. – JaredC Jan 01 '13 at 23:32
7

Take a look at 11.3 paragraph 11:

For a friend class declaration, if there is no prior declaration, the class that is specified belongs to the innermost enclosing non-class scope, but if it is subsequently referenced, its name is not found by name lookup until a matching declaration is provided in the innermost enclosing nonclass scope.

Example:

class X;
void a();
void f() {
  class Y;
  extern void b();
  class A {
  friend class X;  // OK, but X is a local class, not ::X
  friend class Y;  // OK
  friend class Z;  // OK, introduces local class Z.
  friend void a(); // error, ::a is not considered
  friend void b(); // OK
  friend void c(); // error
  };
  X *px;           // OK, but ::X is found
  Z *pz;           // error, no Z is found
}
Community
  • 1
  • 1
aschepler
  • 70,891
  • 9
  • 107
  • 161