Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is the friend declaration a real declaration?

Tags:

c++

C++ Primer says:

It is important to understand that a friend declaration affects access but is not a declaration in an ordinary sense.

So friend declaration should offer access authority only to the friend class/function, it is not a real declaration.

However, I tried this program, it complied successfully and outputs 2 in GCC 5.2.0, what's wrong?

#include <iostream>

class Tmp {
 public:
  Tmp(int a) : a_(a) {};

 private:
  int a_;

  friend void p(Tmp a) { std::cout << a.a_ << std::endl; }
};

// void p(Tmp a); I commented it, so there is not any declaration statement for p(Tmp a).

int main(void) {
  Tmp a(2);
  p(a);
  return 0;
}
like image 819
acgtyrant Avatar asked Aug 24 '15 05:08

acgtyrant


1 Answers

A friend declaration is a real declaration in the technical sense: it is a declaration according to the grammar of the C++ language. The keyword friend is a specifier that modifies a declaration.

If you really want to know what the book means, you should just look at the immediately preceding text.

Classes and nonmember functions need not have been declared before they are used in a friend declaration. When a name first appears in a friend declaration, that name is implicitly assumed to be part of the surrounding scope. However, the friend itself is not actually declared in that scope (§7.2.1, p. 270).

Even if we define the function inside the class, we must still provide a declaration outside the class itself to make that function visible. A declaration must exist even if we only call the friend from members of the friendship granting class.

The friend declaration is different from a typical declaration because most declarations introduce the names they declare into the scope in which they are found, and then those names may be immediately used:

int x;  // introduces the name x into this scope
x = 0;  // lookup of "x" finds the name just declared

A friend declaration introduces the name declared into the nearest enclosing namespace, not the class in which the friend declaration is found. So it is unusual in that sense. However, even more unusually, the name introduced by a friend declaration is not visible to either qualified or unqualified name lookup until the same name is declared at the nearest enclosing scope.

In other words, you may not be able to start using the name immediately after the friend declaration. This is probably what the book means when it says the friend declaration is not a declaration in the ordinary sense.

Here is a simple example:

#include <cstdio>
class C {
    friend void hello() { std::puts("Hello, world!"); }
};
int main() {
    hello();
}

This program is ill-formed because hello was not declared in the global namespace before being called. http://coliru.stacked-crooked.com/a/3ae525122312c96c

Your example only happens to work because there is a special rule that argument-dependent lookup finds friends declared inside associated classes even if they haven't been declared at namespace scope yet. In the call p(a), since a has the class type Tmp, the class Tmp is an associated class.

like image 109
Brian Bi Avatar answered Oct 17 '22 19:10

Brian Bi