简体   繁体   中英

Does an in-class friend of a nested class have access to outer class members?

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 class N if

  • m as a member of N is public, or

  • m as a member of N is private, and R occurs in a member or friend of class N , or

  • m as a member of N is protected, and..., or

  • there exists a base class B of N that is accessible at R , and m is accessible at R when named in class B .

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 .

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM