Friend function in dependent volume

Is this code invalid:

template <class T> struct A; class C { template <class T> friend void A<T>::foo(); }; 

GCC 6.1.0 says:

 error: member 'void A<T>::foo()' declared as friend before type 'A<T>' defined template <class T> friend void A<T>::foo(); 

Clang 3.8.0:

 warning: dependent nested name specifier 'A<T>::' for friend class declaration is not supported; turning off access control for 'C' [-Wunsupported-friend] 

And crashing in Visual Studio 2015:

 fatal error C1001: An internal error has occurred in the compiler. (compiler file 'f:\dd\vctools\compiler\cxxfe\sl\p1\c\template.cpp', line 8952) template <class T> friend void A<T>::foo(); 

More specifically, does A need to be defined before declaring a friend?

  template <class T> struct A; class C { static void foo(); template <class T> friend void A<T>::f(); }; template <class T> struct A { void f() { } }; 

If so, why?

+7
c ++
source share
4 answers

You reference A member function foo . This feature is not yet known, because you are only sending announcement A

In other words, you need to declare A<T>::foo before C , as the GCC message is trying to tell you (the other two are pretty cryptic). This means that you must declare the complete interface A to C instead of just declaring it ahead.

+4
source share

Decision

You can declare f as a friend of C as follows:

 class C; template <class T> struct A { void f(C const &c); }; class C { int i = 42; public: static void foo(); template <class T> friend void A<T>::f(C const &c); }; template <class T> void A<T>::f(C const &c) { std::cout << ci << std::endl; } 

Live demo

Justification

According to the standard ยง3.3.2 / p6 Point of declaration [basic.scope.pdecl]:

After the class member declaration point, the member name may be raised within the class. [Note: this is true even if the class is an incomplete class. For example,

 struct X { enum E { z = 16 }; int b[X::z]; // OK }; 

- end note]

Diagnostics are more likely to be misleading for both GCC and CLANG. The real problem with your code is not that you are trying to access the definition of an incomplete type, but rather that you can only refer to the name of a class member only after it has been declared.

+2
source share

First, declaring a Forward for a class is not enough if you need to use the actual type of the class, for example, if you need to use it as a base class or if you need to use class methods in a method.

Since you are trying to use its "foo ()" data here, the compiler does not know what A :: foo () is. The compiler cannot tell if it is a typo (or) an actual function. Know the declaration of A :: foo () before you can use it.

If you still only want to forward the class declaration and make it a friend, see if the friend classes are appropriate for your situation.

 template <class T> struct A; class C{ template <class T> friend struct A; }; 
0
source share

The first problem (I think) is from & sect; 9.3 / 7 [class.mfct] and possibly some other places in the standard (see clang post and answer 101010 below):

Previously declared member functions may be referred to in friend announcements.

This problem is similar to that of this question .

Since you did not declare A<T>::f before C , you cannot declare that it has a friend C

But there is a hidden problem executing the clang message , if you create an A not templated class, the message is different:

Incomplete type A in a nested name specifier.

Which is closer to the gcc message than to the actual one, is because the clang warning is something else. Per & sect; 14.5.4 / 5 [temp.friend] , the standard allows a class template member to be a friend, so this should be valid:

 template <typename T> struct A { void f (); }; class C { template <typename T> friend void A<T>::f(); // Ok, A<T>::f is already declared void private_member (); // See below }; 

But clang still complains:

warning: the dependent qualifier nested name 'A ::' for declaring a friend's class is not supported; disabling access control for "C" [-Wunsupported-friend]

clang does not support this friend declaration, so it just disables access control for C , which means:

 C c; c.private_member(); 

It will be "valid" everywhere that may not be what you want.

0
source share

All Articles