clang++, g++, and MSVC disagree on this code:
class A {
private:
enum class E { NO, YES };
class B {
private:
friend E f1() { return E::YES; }
// friend E f2();
};
};
// A::E f2() { return A::E::YES; }
int main() {}
clang++ accepts the code as shown. g++ and MSVC complain in f1
that A::E
is inaccessible. If function f2
is uncommented, all three compilers complain at its definition that A::E
is inaccessible.
Is f1
in fact valid?
The relevant Standard pieces I found are:
[class.access.nest]:
A nested class is a member and as such has the same access rights as any other member.
Though this alone doesn't mean friends of the nested class have all the same rights as the nested class.
[class.access.base]/5:
The access to a member is affected by the class in which the member is named. This naming class is the class in which the member name was looked up and found. A member
m
is accessible at the point R when named in classN
if
m
as a member ofN
is public, or
m
as a member ofN
is private, and R occurs in a member or friend of classN
, or
m
as a member ofN
is protected, and..., orthere exists a base class
B
ofN
that is accessible at R, andm
is accessible at R when named in classB
.
So f2
is invalid, because there the naming class for A::E
is definitely A
, there are no base classes involved, and the definition of f2
is not a member or friend of A
and does not "occur in" a member or friend of A
.
In f1
the naming class for unqualified E
is also A
. ([basic.lookup.unqual] says a lookup for the name E
in class A::B
is done first, but it's not "found" there, so then a lookup in class A
is done, and the member is found.) But I guess the big question then is, does the definition of f1
"occur in" a member of A
? That member, if so, would have to be class A::B
.
Can inner class access members of outer class? Yes, including the ones declared private , just as any instance method can.
If the declaration of a nested class is followed by the declaration of a friend class with the same name, the nested class is a friend of the enclosing class.
So, yes; an object of type Outer::Inner can access the member variable var of an object of type Outer .
Not only does the nested class have access to the private fields of the outer class, but the same fields can be accessed by any other class within the package when the nested class is declared public or if it contains public methods or constructors.
I think gcc and msvc are right.
From [class.friend]/1, emphasis mine:
A friend of a class is a function or class that is given permission to use the private and protected member names from the class. A class specifies its friends, if any, by way of friend declarations. Such declarations give special access rights to the friends, but they do not make the nominated friends members of the befriending class.
When you have friend E f1()
, that gives f1
permission to use the private and protected names of B
, specifically. E
is not a private or protected name of B
, it's a name that B
simply has access too.
This is conceptually similar to [class.friend]/10:
Friendship is neither inherited nor transitive.
Since it would imply that the rule is that f1
can access B
's stuff, and B
can access A
's stuff, therefore f1
can access A
's stuff.
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