spraetor
spraetor

Reputation: 451

friend of templated class in anonymous namespace

When declaring a class A as friend of a class B, while A is defined inside an anonymous namespace and B outside, some compilers produce an error "protected member inaccessible" while others do not produce any error or warning. The situation changes if either A or B or both are templates:

namespace {
  template <class T>
  struct A {
    template <class BB>
    void foo(BB const& b) { b.bar(); }
  };
} // end anonymous namespace

template <class T>
class B {
  template <class> friend struct A;

protected:
  void bar() const {}
};

int main() {
  A<int> a;
  a.foo(B<int>{});
}
  1. A and B are both templates. Then Intel icc 18: error #308: function "B<T>::bar [with T=int]" is inaccessible, gcc 7.2: no error, clang 5.0: no error
  2. A is no template while B is template: Intel icc 18: no error, gcc 7.2: error: 'void B<T>::bar() const [with T = int]' is protected within this context, clang 5: no error
  3. A is a template while B is not: Intel icc 18: error #308, gcc 7.2: error, clang 5: no error
  4. neither A nor B are templates: Intel icc 18: no error, gcc 7.2: error, clang 5: no error
  5. neither A nor B are templates (as in 4.) but location of A and B exchanged: Intel icc 18: error #308, gcc 7.2: error, clang 5: error: 'bar' is a protected member of 'B'
  6. A and B are both templates (as in 1.) but location of A and B exchanged: Intel icc 18: error #308, gcc 7.2: no error, clang 5: error

See the example in the compiler explorer: https://godbolt.org/g/6Zdr3c and https://godbolt.org/g/BRqf78 for the case 6.

So, what is the correct behavior? Which compiler is correct?

Upvotes: 4

Views: 622

Answers (1)

Johan
Johan

Reputation: 3881

As far as I can judge from the standard the given code is correct in cases 1-4 and should compile without diagnostics:

The definition of unnamed namespaces (7.3.1.1:1) state that an unnamed namespace definition is equivalent to defining a named namespace with a name unique to the translation unit and then importing this namespace with a using directive.

This will make the declaration of A accessible in the global scope, and according to paragraph 11.3:9

A name nominated by a friend declaration shall be accessible in the scope of the class containing the friend declaration.

Thus the parameterized class A is a friend of B and should be able to access B::bar

In case 5 there is a difference. As far as I can see, the friend declaration declares a new parameterized class A in the enclosing scope which is different from the class A in the unnamed namespace.

Upvotes: 1

Related Questions