Are gcc and clang wrong to accept a friend function accessing a befriended class's private members?

76 Views Asked by At

In a class template A, a different instance of A is befriended. Specifically A<T> and A<T const> befriend each other (see below). This should not mean that friends of, say, A<T> should be able to access private members of A<T const> or vice versa. But apparently gcc and clang accept this.

#include <type_traits>

template <typename T>  
struct A { 
 private:
  T value{};

 public:
  using InvT = std::conditional_t<std::is_const_v<T>, std::remove_const_t<T>, std::add_const_t<T>>;
  friend A<InvT>;

  friend bool operator==(A const& a, A<InvT> const& b) noexcept {
    return a.value == b.value;
    //                  ^^^^^ private. should not be accessible
  }
};

Are they just wrong to accept this?

1

There are 1 best solutions below

0
Brian Bi On BEST ANSWER

This is CWG 1699: if a friend function is defined lexically within the class definition, does the friend get access to everything that the class has access to? Clang and GCC currently consider the answer to be "yes". MSVC considers the answer to be "no". All implementations agree that when the definition of a friend function is outside the class, the body of the function doesn't automatically get access to all names that the class has access to.

In your example, because the operator== in question is defined inside the definition of A<const int>, the friend function gets access to everything that A<const int> has access to, which includes all of A<int>'s private members since A<int> has declared A<const int> to be its friend.

If the friend declaration of operator== is made into a forward declaration and the definition of that operator== is supplied out-of-line, then all three compilers reject the code since friendship is not transitive.

If the inline friend definition is kept but the declaration friend A<InvT>; is removed, then Clang rejects the code but GCC continues to accept it. This is probably a bug in GCC.