I'm trying to figure out while the following code works in GCC 7, but not in GCC 8.1.
What the code does is:
MyGoodFriend
(in global namespace)Befriended
inside the inner
namespaceMyGoodFriend
a friend of Befriended
The problematic piece is
template<class FA>
friend class MyGoodFriend;
I get what the problem is. GCC 8.1 requires me to use the fully-qualified name ::MyGoodFriend
in the friend
declaration - however, GCC 7 was happy with just MyGoodFriend
. This is the code:
template<class A>
class MyGoodFriend;
namespace inner {
template<class T>
class Befriended {
private:
int i;
T t;
template<class FA>
friend class MyGoodFriend;
// This works for gcc 8.1:
// template<class FA>
//friend class ::MyGoodFriend;
};
} // namespace inner
template<class A>
class MyGoodFriend {
public:
void do_something() {
inner::Befriended<bool> bf;
bf.i = 42;
}
};
int main() {
MyGoodFriend<int> mgf;
mgf.do_something();
}
You can test this with GCC 7 vs 8 here: https://godbolt.org/g/6u9rgy
Two questions:
Was GCC 7 misinterpreting the standard? Or is this a mistake in GCC 8?
If I read the standard correctly (referring to the C++14 standard here): Section 3.4 (which specifies how name lookup works), Point 7.4 states:
A name used in the definition of a class X […]
- if X is a member of namespace N, or is a nested class of a class that is a member of N, or is a local class or a nested class within a local class of a function that is a member of N, before the definition of class X in namespace N or in one of N ’s enclosing namespaces
Obviously, MyGoodFriend
is declared in an enclosing namespace, so it should be visible in Befriended
- right?
Thanks for any help!
From [namespace.memdef]/3, emphasis mine (the wording is the same in C++11):
If a friend declaration in a non-local class first declares a class, function, class template or function template99 the friend is a member of the innermost enclosing namespace. [...] If the name in a friend declaration is neither qualified nor a template-id and the declaration is a function or an elaborated-type-specifier, the lookup to determine whether the entity has been previously declared shall not consider any scopes outside the innermost enclosing namespace.
That is, when you write:
template<class FA>
friend class MyGoodFriend;
We only look for inner::MyGoodFriend
, not ::MyGoodFriend
. Since we don't find it, we consider it to be a forward declaration of the class template inner::MyGoodFriend
. As a result, ::MyGoodFriend
is not friend
ed.
With the revision, gcc 7 compiled likely because of one of the many template-access related bugs. See this meta-bug. gcc 8's behavior is correct.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With