Reputation: 451
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>{});
}
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 errorA
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 errorA
is a template while B
is not: Intel icc 18: error #308
, gcc 7.2: error, clang 5: no errorA
nor B
are templates: Intel icc 18: no error, gcc 7.2: error, clang 5: no errorA
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'
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
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