简体   繁体   中英

Member access control for friend function defined inside class in C++

I understand that the following C++ code snippet should produce an error in the definition of g , because ptx is private and cannot be accessed there.

class P {
  class T {
    int x;
    friend class P;
  };
  T t;

  friend void g(P &p);
};

void g(P &p) { p.t.x = 42; }

What puzzles me is the next snippet. It differs only in the fact that the definition of the friend function g now occurs inside class P .

class P {
  class T {
    int x;
    friend class P;
  };
  T t;

  friend void g(P &p) { p.t.x = 42; }
};

Clang++ (both 6.0.0-1ubuntu2 and Apple version clang-1100.0.33.8) compiles the latter with no error, whereas GNU C++ (7.5.0-3ubuntu1~18.04) produces the same error as in the former snippet.

I understand that the function g defined in the latter case is not in the same scope as the one defined in the former (cf. a related question and an older longer discussion ) and it's only visible through ADL. But I think what I'm asking here is different: should the declaration friend class P in class T extend to the body of friend function g or not?

The relevant part of the C++ standard (§11.3 or §11.9.3 in more recentdrafts ) states that:

7... A friend function defined in a class is in the (lexical) scope of the class in which it is defined. A friend function defined outside the class is not (6.5.1).

So I understand that Clang++ and GNU C++ interpret differently what is meant by "lexical scope" (see also this answer to the previous related question). Clang++ seems to compile g as if it were a friend of class T , probably because it's in the lexical scope of class P which is a friend of class T , whereas GNU C++ does not.

  1. Is there a bug in one of the two compilers?
  2. If yes, which one?
  3. Regardless of the answers to the previous questions, isn't this something that the standard should formalise better?

This looks like CWG1699 (which is still open).

1699. Does befriending a class befriend its friends?

According to 14.3 [class.friend] paragraph 2,

Declaring a class to be a friend implies that the names of private and protected members from the class granting friendship can be accessed in the base-specifiers and member declarations of the befriended class.

A friend declaration is a member-declaration , but it is not clear how far the granting of friendship goes in a friend declaration. For example:

 class c { class n {}; friend struct s; }; struct s { // #1 and #2 are not relevant for this question friend void f() { c::n(); } // #3 };

In particular, if a friend function is defined inside the class definition, as in #3, does its definition have access to the private and protected members of the befriending class? Implementations vary on this point.

For starters - disclaimer: this is my interpretation of the standard and even though I think it's the right one, one can't be sure what was really meant.

tl;dr

  1. Yes.
  2. IMO clang++
  3. If you look below you will notice it is formalised pretty good.

Full answer

Having said that I think there are two relevant quotes from the standard. First is this:

11.9 Member access control

1 A member of a class can be

(1.1) - private; that is, its name can be used only by members and friends of the class in which it is declared.

and the second is:

11.9.3 Friends [class.friend]

1 A friend of a class is a function or class that is given permission to use the private and protected member names from the class. A class specifies its friends, if any, by way of friend declarations. Such declarations give special access rights to the friends, but they do not make the nominated friends members of the befriending class .

From these two one can deduce a few things. But the most important one is that even inline friend cannot access private members of class defined inside befriended class. Why? Because it is neither member nor friend of the nested class. And from that it seems the g++ is right here.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM