Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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 p.t.x 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 recent drafts) 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?
like image 278
nickie Avatar asked Apr 15 '20 10:04

nickie


1 Answers

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.

like image 176
Language Lawyer Avatar answered Oct 15 '22 00:10

Language Lawyer