Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does friendship seem transitive with befriended function templates?

Friendship is not supposed to be transitive. That is, my friends cannot access each other's privates (unless they're also friends).

However, with the following function template that is defined inside a befriending class template, this seems to be the case:

template <typename T>
class A {
  template <typename>
  friend class A; // all other A instances are my friend

  int i{}; // some private member

  template <typename U>
  friend int test(A at, A<U> au) { // int test(A<T>, A<U>) is my friend
    return at.i + au.i;
  }
};

int main() {
  A<int> ai;
  A<char> ac;
  test(ai,ac);
}

I stumbled over this in a setting where test was called operator+ but the principle is the same as in this minimal example.

The way I see it A<int> befriends A<char> as well as a free function int test(A<int>, A<char>). Which means that those can access A<int>::i. However, A<char> in turn befriends some hypothetical function int test(A<char>, A<int>) but I don't see it befriending int test(A<int>, A<char>) anywhere. Crucially, test is not a member function of any A, despite being defined inside A's body.

Yet, int test(A<int>, A<char>) can access both A<int>::i and A<char>::i, despite both being private.

Both gcc and clang seem to accept this. Which means that I misunderstood something. Or both compilers are in error, which is probably not the case.

Note that they both stop accepting the code if one removes the friendship with other A instances unless one also moves the function template definition past the class template.

What friendship rules dictate that this example is legal? I'm assuming C++23.

like image 287
bitmask Avatar asked Dec 09 '25 07:12

bitmask


1 Answers

This is CWG1699.

[class.access.base]/5.2 says:

A member m is accessible at the point R when named in class N if:

  • m as a member of N is private, and R occurs in a direct member or friend of class N

but it is not clear whether an access from the body of a friend function defined within a class C is considered to 'occur in' C for the purpose of this definition.

From the issue:

There are two lines of analysis that lead to opposite conclusions. The first is that a friend defined within the member-specification is written by the class author and is effectively part of the class, not subject to hijacking by other declarations, and thus should be afforded the same access as all other declarations that are part of the class. The second is that giving different access to a friend function based simply on whether it was defined inside or outside of its befriending class is confusing.

like image 179
duck Avatar answered Dec 10 '25 20:12

duck



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!